foo
findで見つけたすべての結果に対して実行したいプログラムがあります。だからこんな感じ:
find . -name '*.o' -type f -exec foo {} \;
foo
特定の文字列バーへのすべての呼び出しの出力を把握したいと思います。だから私はこれを追加します:
find . -name '*.o' -type f -exec foo {} \; | grep bar
しかし、一致がどのファイルから来たのかに関する元の情報を失いました。コマンド -fprintf /dev/stderr '%p\n'
に追加しようとしましたが、grepの結果が印刷されず、stdoutが消えているようです。find
各ファイル名を出力に印刷し、そのファイルに対応するgrep結果を印刷するにはどうすればよいですか?
-H
あるいは、引数を操作する方法があればgrep
良いと思いますが、書かれているように標準入力からテキストを渡し、ファイルgrep
名がわからないので動作しません。私は様々な注文を試しましたが、xargs
何も効果がありませんでした。
答え1
各ファイル名を出力に印刷し、そのファイルに対応するgrep結果を印刷するには、-exec foo {} | grep
パイプをシェルにラップします。
find . -name '*.o' -type f -print -exec sh -c 'foo "$1" | grep "bar"' sh {} \;
-H
grepの引数が標準入力と連携するようにするには、バージョンがオプションをサポートしている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 {} +
答え2
各ファイル名を出力に印刷し、そのファイルに対応するgrep結果を印刷するにはどうすればよいですか?
1.)2つのgrepインスタンスを使用します。 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を実行する問題は解決されません。
答え3
これは見苦しいですが、次のようにすれば役に立ちます。
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@"' _ {} \;