数百のファイルのリストに対してgrepを実行しようとしています。
_$ head -n 3 <(cat files.txt)
admin.php
ajax/accept.php
ajax/add_note.php
_
ただし、ファイルで見つかったことがわかっている文字列をgreppingしている場合でも、以下はファイルを検索しません。
_$ grep -i 'foo' <(cat files.txt)
$ grep -i 'foo' admin.php
The foo was found
_
ファイルからpatternsを読み取る_-f
_フラグに精通しています。しかし、入力ファイルを読み取る方法は?
cp
は<(cat files.txt)
形式をサポートしているようで、そこからファイルをgrepするので、ファイルを一時ディレクトリにコピーするという恐ろしい回避策を検討しました。 シャーリーより良い方法があります。
ファイル自体ではなく、ファイル名のリストをgrepしているようです。 <(cat files.txt)
はファイルをリストするだけです。 <(cat $(cat files.txt))
を試して実際にそれらを連結し、単一のストリームとして検索するか、または
grep -i 'foo' $(cat files.txt)
すべてのファイルをgrepに提供します。
ただし、リストにファイルが多すぎる場合は、引数の数に問題がある可能性があります。その場合、私はただ書きます
while read filename; do grep -Hi 'foo' "$filename"; done < files.txt
xargs grep -i -- foo /dev/null < files.txt
ファイルが空白または改行で区切られていると想定します(引用符またはバックスラッシュを使用して、これらの区切り文字をエスケープできます)。 GNU xargs
を使用すると、-d
で区切り文字を指定できます(これにより、引用処理が無効になります)。
(unset -v IFS; set -f; grep -i -- foo $(cat files.txt))
ファイルがスペース、タブ、または改行で区切られていると想定します(IFS
に割り当てることで別のセパレーターを選択できますが、それらをエスケープする方法はありません)。ほとんどのシステムでファイルリストが大きすぎる場合、この方法は失敗します。
それらはまた、どのファイルも-
と呼ばれていないと想定しています。
Stdinからファイル名のリストを読み取るには、xargs
を使用できます。例えば。、
cat files.txt | xargs -d'\n' grep -i -- 'foo'
デフォルトでは、xargs
は、ブランクで区切られた項目を標準入力から読み取ります。 -d'\n'
は、引数の区切り文字として改行を使用するように指示し、空白を含むファイル名を処理できるようにします。 (StéphaneChazelasが指摘するように、これはGNU拡張子です)。ただし、改行を含むファイル名には対応していません。これらを処理するには、もう少し複雑なアプローチが必要です。
FWIW、bashのread
コマンドは文字単位でデータを読み取るのに対し、xargs
は入力をより効率的に読み取るため、このアプローチはwhile read
ループよりも多少高速です。また、xargs
はgrep
コマンドを必要な回数だけ呼び出すだけで、各呼び出しは複数のファイル名を受け取ります。これは、ファイルごとにgrep
を呼び出すよりも効率的です。名前。
詳細は xargs man page とxargs info pageを参照してください。
xargs
は、ファイルからアイテムを読み取ることができます(files.txt
list)オプション付き:
--arg-file=file
-a file
Read items from file instead of standard input. If you use this
option, stdin remains unchanged when commands are run. Other‐
wise, stdin is redirected from /dev/null.
だからこれもうまくいくはずです:
xargs -a files.txt grep -i 'foo'
またはファイル名のスペース
xargs -d'\n' -a files.txt grep -i 'foo'
xargs -I{} -a files.txt grep -i 'foo' {}
Forも実行できますが、Orionの例が最も簡単です。
for i in $(cat files.txt); do grep -i 'foo' $i ; done
(files.txtにリストされている各ファイルに対して、grepコマンドを実行します。)