Grep:manページから見出しの単語を検索すると予期しない結果


19

macOSでmanページをgrepしようとすると、奇妙な動作になります。たとえば、Bashのマニュアルページには次の文字列が明確に記載されていますNAME

$ man bash | head -5 | tail -1
NAME

そして、私がgrepしnameた場合、結果が得られますが、私がgrepした場合、結果は得られNAMEません:

$ man bash | grep 'NAME'
$ man bash | grep NAME

私はそこにあることがわかっている他の大文字の単語を試しましたが、SHELLyields を検索すると何も得られませんが、BASHyieldsを検索すると結果が得られます。

何が起きてる?

更新:すべての回答をありがとう!これに遭遇したコンテキストを追加する価値があると思いました。ラップするbash関数を作成したかったのでman、シェルビルトインのマニュアルページを検索しようとした場合は、Bashのマニュアルページの関連セクションにジャンプしてください。より良い方法があるかもしれませんが、ここに私が現在持っているものがあります:

man () {
  case "$(type -t "$1")" in
    builtin)
      local pattern="^ *$1"

      if bashdoc_match "$pattern \+[-[]"; then
        command man bash | less --pattern="$pattern +[-[]"
      elif bashdoc_match "$pattern\b"; then
        command man bash | less --pattern="$pattern[[:>:]]"
      else
        command man bash
      fi
      ;;
    keyword)
      command man bash | less --hilite-search --pattern='^SHELL GRAMMAR$'
      ;;
    *)
      command man "$@"
      ;;
  esac
}

bashdoc_match() {
  command man bash | col -b | grep -l "$1" > /dev/null
}


どのオペレーティングシステムを使用していますか?受け入れられた答えは正しいと確信していますが、IOはArch Linuxボックスでこれを再現できませんでした。man bash | grep NAME期待どおりに動作します。
テルドン

@terdon私はmacOSを使用しています。Bash 3.2および4.4.5でこの動作が発生する
-ivan

余談ですが、組み込みhelpコマンドを検出した場合は、bash コマンドを使用してその情報を取得できます。
ジョー

@Joe問題は、help結果があまりにも多く残されていることが多いことです。たとえば、チェックアウトhelp completecompleteセクションのセクションをご覧くださいman bash
イヴァン

回答:


33

印刷できない文字を表示する| sed -n lためにそのtailコマンドにを追加すると、おそらく次のようなものが表示されます。

N\bNA\bAM\bME\bE

つまり、各文字はXBackspace として書き込まれXます。現代の端末では、文字はそれ自体に書き込まれます(Backspace aka BS aka \baka ^Hはカーソルを1列左に移動する文字であるため)違いはありません。しかし、古代のテレタイプライターでは、インクが2倍になるとキャラクターが太字で表示されます。

それでも、more/のようなページャーlessはそのフォーマットを太字を意味すると理解しているので、roff太字のテキストを出力するのはそれでもです。

一部の人の実装はroff、それらのシーケンスが使用されない方法で呼び出し(またはcol -b -p -xman-db実装の場合のように(MAN_KEEP_FORMATTING環境変数が設定されていない限り)内部的にそれらを除去するために呼び出します)、出力を検出したときにページャーを呼び出しませんターミナルには行きません(そこでman bash | grep NAME動作します)が、あなたには行きません。

col -bこれらのシーケンスを削除するために使用できます(下線には他のタイプ(_BS X)もあります)。

GNUを使用するシステムroff(GNUやFreeBSDのように)、あなたはそれらの配列が確認することにより、最初の場所で使用されるのを避けることができます-c -b -uオプションが渡されgrottyていることを確認して、例えば、-P-cbuに渡されるオプションをgroff

たとえば、次をgroff含むというラッパースクリプトを作成します。

#! /bin/sh -
exec /usr/bin/groff -P-cbu "$@"

で/ usr / bin / groffの前に置くこと$PATH

macOS ' man(またGNUを使用roff)を使用するman-no-overstrike.confと、次のものを作成できます。

NROFF /usr/bin/groff -mandoc -Tutf8 -P-cbu

そして次のように呼び出しmanます:

man -C man-no-overstrike.conf bash | grep NAME

それでもGNU roffでは、GROFF_SGR環境変数を設定する(またはGROFF_NO_SGRコンパイル時にデフォルトがどのように設定されているかに応じて変数を設定しない)と、grotty-cオプションが渡されない限り)代わりにANSI SGR端末エスケープシーケンスが使用されますキャラクター属性のためのこれらのBSトリックの。オプションでless呼び出されたときにそれらを理解し-Rます。

FreeBSDの男は、MANCOLOR変数を設定してを要求grottyする-c場合を除き、このオプションを使用して呼び出します(この場合、ANSI SGRエスケープシーケンスを使用するデフォルトに-c渡されgrottyずにgrotty戻ります)。

MANCOLOR=1 man bash | grep NAME

そこで動作します。

Debianでは、GROFF_SGRはデフォルトではありません。もしあなたがそうするなら:

GROFF_SGR=1 man bash | grep NAME

ただし、manのstdoutは端末ではないため、GROFF_NO_SGR変数を渡すためにそれ自体をgrotty使用col -bpxします(colSGRシーケンスをストリップする方法がわからない場合でも、BSシーケンスをストリップするために使用できると思いますそれはでないMAN_KEEP_FORMATTING)私たちを上書きしていますGROFF_SGR。代わりに次のことができます:

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(ターミナルで)SGRエスケープシーケンスを使用します。

そのとき、それらのNAMEの一部がターミナル(およびless -Rページャー)で太字で表示されていることに気付くでしょう。出力をsed -n lMANPAGER='sed -n /NAME/l')にフィードすると、次のように表示されます。

\033[1mNAME\033[0m$

\e[1mANSI互換端末で太字を有効にするシーケンスと\e[0m、すべてのSGR属性をデフォルトに戻すシーケンスはどこにありますか。

そのテキストにgrep NAMEテキストが含まれている場合と同様に動作しますNAMEが、それの部分だけが太字/下線である場合、テキストを探しているならば、あなたはまだ問題を抱えている可能性が...


2
うわー、そこに物理的なテレタイプの遺産を見るのはかなり興味深い。インクの2倍=>太字。完璧な意味
イヴァン

1
sed -n l代わりとして愛していますod
トム・ヘイル

13

マニュアルページを見ると、ヘッダーが太字になっていることがわかります。これは、制御文字で書式設定することで実現されます。grepあなたが望んでいるようにできるようにするには、これらを取り除く必要があります。

このためにcolユーティリティを使用できます。

$ man bash | col -b | grep 'NAME'

この-bオプションには、OpenBSDに関する次の説明があります。

バックスペースを出力せず、各列位置に書き込まれた最後の文字のみを出力します。これは、mandoc(1)の出力の処理に役立ちます。


Linuxのcolマニュアル(Ubuntuの場合)には最後の文がありません(ただし、同じように機能します)。

Linuxでは、設定解除MAN_KEEP_FORMATTING環境変数を(または空の文字列に設定する)にも役立つかもしれない、とにあなたをできるようになりますgrepの出力通過することなくmanスルーcol -b


(ArchとUbuntuシステムでこれをテストしたように)Linuxではこれは必要ないか、もう必要ないと思います。両方のシステムNAMEで、bashのマニュアルにあるのはNAMEno \bです。
テルドン

@terdon私は最初にmacOSの言及に気付かなかったので、間違って構成されたLinuxシステムが可能性があると思いました。Linuxのビットを削除しました。
クサラナナンダ

あなたは何も見逃していませんでした。Linuxで再現できないため、彼らが使用しているOSをOPに尋ねました。そして、私はあなたが間違っていたことを暗示していませんでした。私が知っているのはMAN_KEEP_FORMATTING、あなたが言うように変数が正確に機能するLinuxディストリビューションがあることです。いつもそうではないことを指摘したかっただけです。
テルドン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.