Grep:マニュアルページでタイトル内の単語を検索すると予期しない結果が発生する

Grep:マニュアルページでタイトル内の単語を検索すると予期しない結果が発生する

macOSでマニュアルページを検索しようとすると、奇妙な動作が発生します。たとえば、Bash のマニュアルページには次の文字列が目立つように表示されますNAME

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

grepを実行するとname結果が得られますが、grepを実行すると結果はNAME得られません。

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

私が知っている他の大文字の単語を試してみましたが、検索SHELL結果が出ませんでしたBASH

ここで何が起こっているのでしょうか?

修正する:すべての回答ありがとうございます!この問題が発生した理由の背景を追加する価値があると思いました。私はWrapの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
}

ベストアンサー1

印刷できない文字を表示するためにコマンド| sed -n lにaを追加すると、次の内容が表示されることがあります。tail

N\bNA\bAM\bME\bE

つまり、各文字はXBackspaceで作成されますX。最新の端末では文字自体を上書きするので(バックスペース(BSとも呼ばれる)はカーソルを1列左に移動する文字なので\b)何の違いもありません。^Hしかし、古代テレタイプではインクの量が2倍なので、文字が太字で表示されます。

それにもかかわらず、more/のようなポケットベルはフォーマットlessが太字で表示されることを理解しているので、これはまだroff太字のテキストを出力する方法です。

一部の実装では、roffこれらのシーケンスを使用しない方法でそれを呼び出す(または実装のようにそれをcol -b -p -x削除するために内部的に呼び出されますman-dbMAN_KEEP_FORMATTING環境変数が設定されていない場合))、出力が次の場合にページャを呼び出さない。検出されて端末に移動しませんが(そこでman bash | grep NAME作業しても大丈夫です)、端末には移動しません。

を使用して、これらのシーケンス(他のタイプ(BS)とアンダースコアもcol -bあります)を削除できます。_X

GNU(GNUやFreeBSDなど)を使用するシステムでは、roffオプションがに渡されることを確認して最初からこれらのシーケンスを使用しないことがあります。-c -b -ugrotty-P-cbugroff

groffたとえば、「include」というラッパースクリプトを作成すると、次のようになります。

#! /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)(オプションが渡されない限り)、ANSI SGR端末エスケープシーケンスが使用されます。 。役割属性のナンセンスです。オプションを呼び出すときはこれを理解してください。GROFF_NO_SGRgrotty-cless-R

FreeBSDの人はあなたが要求しない限りgrottyこのオプションを呼び出すでしょう-cMANCOLOR変数を設定します(この場合、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ので(まだ実行していてもSGRシーケンスを削除する方法がわからないため、BSシーケンスを削除するgrottyために使用できるようです)上書きされます。私たちの。col -bpxcolMAN_KEEP_FORMATTINGGROFF_SGR

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(端末から)SGRエスケープシーケンスを取得します。

その時点で、次のいくつかが見つかります。名前sは端末(およびポケットベル)に太字で表示されますless -R。出力をsed -n l()に入力すると、MANPAGER='sed -n /NAME/l'次の内容が表示されます。

\033[1mNAME\033[0m$

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

これがgrep NAME機能する方法は、テキストにその内容が含まれていることですNAME。ただし、テキストの一部だけが太字/下線付きのテキストを見つけると、問題が発生する可能性があります。

おすすめ記事