
ソース ツリー内のファイルをコンテンツ別に再帰的に検索したいです。grep を使用して次の操作を試しました。
$ grep -rn printf | grep %s | grep bcm_errmsg\(rv\)
これにより、希望どおりにすべての行が返されますが、今度は一致する各ファイルのファイル名を取得したいので、次のように変更しました。
$ grep -rn printf | grep %s | grep -l bcm_errmsg\(rv\)
しかし、ファイル名を印刷する代わりに、
(standard input)
sed
stdout に出力されます。各ファイル名とパス (使用するもの)を取得するには、これをどのように修正すればよいでしょうか?
私がやりたいこと:printf
およびを含む行を持つすべてのファイルを検索し%s
、bcm_errmsg(rv)
見つかったファイルに次の sed コマンドを適用します。
sed -i 's/%s/%d/g; s/bcm_errmsg(rv)/rv/g;'
答え1
物事を複雑にしすぎていると思います。foo
現在のディレクトリとサブディレクトリにあるすべてのファイルで文字列を検索するには、単に次のコマンドを実行します。
grep -r "foo" *
デフォルトでは、grep は一致する行を、見つかったファイル名の先頭に付けて出力します。
代わりに、次の例では、一致する行を除いてファイル名のみが出力されます。
grep -rl "foo" *
答え2
@steeldriver の最初のアイデアに従って、次の操作を実行できます。
egrep -rl '.*printf.*%s.*bcm_errmsg\(rv\).*' . | xargs -d '\n' sed -i '/printf/ s/%s/%d/; /printf/ s/bcm_errmsg(rv)/rv/'
答え3
grep -rlZP '(?=.*printf)(?=.*%s)(?=.*bcm_errstr\(rv\))' . |
xargs -r0 sed -i -e '
/%s/!b
/printf/!b
/bcm_errstr(rv)/!b
s/%s/%d/g;s/bcm_errstr(rv)/rv/g
'
まず、現在のディレクトリから再帰ディレクトリを実行し、printf、%s、bcm_errstr(rv) という文字列が同じ行にあるファイルをスキャンします。順序は問いません。grep
これを行うのに役立つオプションは次のとおりです。
-r
=> 現在のディレクトリとその下のすべてのファイルを再帰的に起動します。-l
=> は、基準に一致するファイル名、つまり 3 つの文字列すべてを同じ行にリストします。-Z
=> 選択されたファイル名は通常の改行文字 (\n) ではなく null で区切られる (\0) ため、あらゆる種類のファイル名に対応できます。-P
=> Perl 正規表現エンジンを有効にして、先読みを使用して 3 つの文字列が同じ行に存在するかどうかを判断できるようにします。
パイプの反対側では、xargs
\0 で区切られたファイル名の受信を待機しています。次に、可能な限りすべてのファイル名を sed コマンドラインに渡します。前回の質問で既にご存知の sed コマンドでは、同じ行に 3 つの文字列が含まれている行に対してのみサブルーチンを実行します。