web-dev-qa-db-ja.com

ファイル名をgrepと一緒に出力すると、find-execになります

fooというプログラムがあり、findで見つかった結果ごとに実行したいと思います。だからこのようなもの:

find . -name '*.o' -type f -exec foo {} \;

特定の文字列バーに対するfooのこれらすべての呼び出しの出力をgrepしたいと思います。だから私はこれを追加します:

find . -name '*.o' -type f -exec foo {} \; | grep bar

しかし、一致がどのファイルから来ているかについての元の情報を失います。 findコマンドに-fprintf /dev/stderr '%p\n'を追加しようとしましたが、grepの結果が出力されないため、stdoutがなくなったように見えます。

各ファイル名を出力に出力して、そのファイルに対応するgrep結果を後で印刷するにはどうすればよいですか?

あるいは、grep-H引数を機能させる方法があれば、それでも問題ありませんが、書かれているように、stdinからテキストを渡すだけで、grepがファイル名。 xargsのさまざまな呪文を試しましたが、どれも機能しませんでした。

2
Zachary Turner

各ファイル名を出力に出力し、その後にそのファイルに対応するgrep結果を出力するには、-exec foo {} | grepパイプをシェルでラップできます。

find . -name '*.o' -type f -print -exec sh -c 'foo "$1" | grep "bar"' sh {} \;

Grepの-H引数を標準入力で機能させるには、ご使用のバージョンのgrep--label=オプションをサポートしている場合に実行できます。

find . -name '*.o' -type f -exec sh -c '
  foo "$1" | grep -H --label="$1" "bar"
' sh {} \;

または(検索結果が+の代わりに\;マルチ引数をサポートしている場合):

find . -name '*.o' -type f -exec sh -c '
  for f; do foo "$f" | grep -H --label="$f" "bar"; done
' sh {} +
3
steeldriver

これはかなり醜いですが、それはあなたのために働くでしょう:

find . -name '*.o' -type f -exec sh -c 'foo "$1" | sed "s@^@$1\t@"' _ {} \;

これにより、各行の先頭にファイル名とタブが配置されます。裸の下線は、生成されたシェルの$0に入力され、ファイル名を$1のままにする文字列です。これで、findの出力をgrepでき、ファイル名が出力に表示されます。


これは、@文字を含むファイル名では機能しません。それが懸念される場合は、シェルスクリプトを拡張できます。

find . -name '*.o' -type f -exec sh -c '
    r=$(echo "$1" | sed "s/@/\\\\\\\\@/g")
    foo "$1" | sed "s@^@$r\t@"
' _ {} \;

8つのバックスラッシュは試行錯誤によって決定されました...

または、便利な「検索と置換」パラメーター置換があるbash(またはksh)を使用する

find . -name '*.o' -type f -exec ksh -c 'foo "$1" | sed "s@^@${1//@/\\\\@}\t@"' _ {} \;
1
glenn jackman

各ファイル名を出力に出力して、そのファイルに対応するgrep結果を後で印刷するにはどうすればよいですか?

1。) grepの2つのインスタンスを使用します。1つはファイル名の印刷用で、もう1つは一致の印刷用です。

find . -name '*.o' -type f -exec grep -l bar {} \; -exec grep bar {} \;

2。) grepを複数のファイルであるかのように動作させます:

find . -name '*.o' -type f -exec grep bar {} /dev/null \;

これでは、例のように[..]-exec foo {} \;[...]とパイプ内でgrepを実行する場合の問題は解決されません。

0
nath