私が探しているものはここにあるものとほとんど同じですが、結果に「行番号、区切り文字、ファイル名、改行」の形式を使用して、ファイル名の後ではなく、行の先頭に行番号を表示します、および一致を含む行を表示しません。
このフォーマットが望ましい理由は、
(b)パターンに一致する行が長すぎる可能性があり、標準出力に表示される(および標準出力での出力は、ファイルに保存し、viなどのツールを使用して、出力ファイルの行ごとに1行を表示するよりも優れています。
要件を設定したので、次のことを考慮してください。
使用しているLinuxホストにAckがインストールされていないため、使用できません。
以下を実行すると、シェルはfind .
を実行し、「find。」を現在の作業ディレクトリから始まり、再帰的に進む絶対パスのリストに置き換えます。
grep -n PATTERN $(find .)
次に、-nは行番号を出力しますが、必要な場所は出力しません。また、何らかの理由で理解できません。ディレクトリ名にPATTERNが含まれている場合、grepは、パターンを含む通常のファイルに加えて、それを照合します。これは私が欲しいものではないので、私は以下を使用します:
grep -n PATTERN $(find . -type f)
また、このコマンドを変更して、findの出力が動的にgrepに渡されるようにしました。最初に絶対パスのリスト全体を作成してから、それらの大部分をgrepに渡す必要はなく、リストを作成するときに各行をgrepに渡すようにしてください。
find . -exec grep -n PATTERN '{}' \;
man page
によると、これは正しい構文のように見えますが、このコマンドを発行すると、Bashシェルの実行が約100倍遅くなるため、これは適切な方法ではありません。
私が説明した内容に照らして、このコマンドに似たものを実行して、目的の形式を取得するにはどうすればよいでしょうか。私はすでに関連する投稿に関連する問題をリストしました。
grep
を使用する代わりに、-r
スイッチをfind
に再帰的に再帰できないのはなぜですか? -n
スイッチの代わりに、使用するスイッチが2つあります。
$ grep -rHn PATTERN <DIR> | cut -d":" -f1-2
$ grep -rHn PATH ~/.bashrc | cut -d":" -f1-2
/home/saml/.bashrc:25
-r
-ファイルとディレクトリを再帰的に検索します-H
-一致する場合はファイル名を出力します(-l
より制限が少ない)。つまり、grep
の他のスイッチで機能します-n
-一致の行番号を表示します$ grep -rHn PATH ~/.bash* | cut -d":" -f1-2
/home/saml/.bash_profile:10
/home/saml/.bash_profile:12
/home/saml/.bash_profile_askapache:99
/home/saml/.bash_profile_askapache:101
/home/saml/.bash_profile_askapache:118
/home/saml/.bash_profile_askapache:166
/home/saml/.bash_profile_askapache:218
/home/saml/.bash_profile_askapache:250
/home/saml/.bash_profile_askapache:314
/home/saml/.bash_profile_askapache:2317
/home/saml/.bash_profile_askapache:2323
/home/saml/.bashrc:25
$ find . -exec sh -c 'grep -Hn PATTERN "$@" | cut -d":" -f1-2' {} +
$ find ~/.bash* -exec sh -c 'grep -Hn PATH "$@" | cut -d":" -f1-2' {} +
/home/saml/.bash_profile:10
/home/saml/.bash_profile:12
/home/saml/.bash_profile_askapache:99
/home/saml/.bash_profile_askapache:101
/home/saml/.bash_profile_askapache:118
/home/saml/.bash_profile_askapache:166
/home/saml/.bash_profile_askapache:218
/home/saml/.bash_profile_askapache:250
/home/saml/.bash_profile_askapache:314
/home/saml/.bash_profile_askapache:2317
/home/saml/.bash_profile_askapache:2323
/home/saml/.bashrc:25
本当にfind
を使用したい場合は、grep
を使用してファイルを検索するときに、このようにfind
を実行できます。
grep -n PATTERN `find . -type f`
コマンド置換の出力は、空白で区切られたファイル名のワイルドカードパターンのリストとして解釈されるため、これは悪いことです。ファイル名に空白または\[*?
のいずれかが含まれている場合、このスニペットは機能しません。また、一致するファイルが多数ある場合、最終的にはコマンドラインが長すぎます。
find . -exec grep -n PATTERN '{}' \;
これは問題なく信頼できますが、grep
はファイルごとに1回呼び出されます。これがとても遅い理由です。
-exec … {} +
を使用して、できるだけ多くのファイルのバッチでコマンドを実行します。最後のバッチ(または理論的には他のバッチ)が単一のファイルで構成される場合があるので、grep
はファイル名を出力しないことに注意してください。 -H
オプションを渡して、常にファイル名を出力するか、引数/dev/null
を追加します(一致するものは含まれませんが、grep
が少なくとも2つのファイル名を確認できるようにします)。
find . -type f -exec grep -Hn PATTERN {} +
GNU grepには、一致する行番号を印刷するオプションはありませんが、一致する行テキストを印刷するオプションはありません。一致するテキストを削除し、行番号をファイル名とsedで置き換えることができます。
find . -type f -exec grep -Hn PATTERN {} + | sed 's/^\([^:]*\):\([^:]*\):.*/\2:\1/'
行番号を右揃えにしたい場合、awkは、私が考えることができる他のどの方法よりもはるかに単純です。
find . -type f -exec grep -Hn PATTERN {} + | awk -F : '{printf "%8d:%s", $2, $1}'
Grepの代わりにawkでマッチングを行うことで、より細かく制御できます。 Awkはインタプリタ言語を備えたより汎用的なツールであるため、少し遅くなる傾向があります。 1つの利点は、コロンまたは改行を含むファイル名の処理方法を選択できることです。これにより、grepからのあいまいな出力が発生します。次のスニペットは、awkを使用して検索を実行し、:
(および改行も含むが、あいまいな出力を生成する)を含むファイル名を処理します。 awkはgrep -E
のように 拡張正規表現 を使用することに注意してください(わずかな違いはありますが、grepまたはawkの実装間で得られる以上のものではありません)。
find . -type f -exec awk '/PATTERN/ {printf "%d:", FNR; print FILENAME}' {} +