web-dev-qa-db-ja.com

リストのgrepファイル

数百のファイルのリストに対して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するので、ファイルを一時ディレクトリにコピーするという恐ろしい回避策を検討しました。 シャーリーより良い方法があります。

15
dotancohen

ファイル自体ではなく、ファイル名のリストを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
22
orion
xargs grep -i -- foo /dev/null < files.txt

ファイルが空白または改行で区切られていると想定します(引用符またはバックスラッシュを使用して、これらの区切り文字をエスケープできます)。 GNU xargsを使用すると、-dで区切り文字を指定できます(これにより、引用処理が無効になります)。

(unset -v IFS; set -f; grep -i -- foo $(cat files.txt))

ファイルがスペース、タブ、または改行で区切られていると想定します(IFSに割り当てることで別のセパレーターを選択できますが、それらをエスケープする方法はありません)。ほとんどのシステムでファイルリストが大きすぎる場合、この方法は失敗します。

それらはまた、どのファイルも-と呼ばれていないと想定しています。

8

Stdinからファイル名のリストを読み取るには、xargsを使用できます。例えば。、

cat files.txt | xargs -d'\n' grep -i -- 'foo'

デフォルトでは、xargsは、ブランクで区切られた項目を標準入力から読み取ります。 -d'\n'は、引数の区切り文字として改行を使用するように指示し、空白を含むファイル名を処理できるようにします。 (StéphaneChazelasが指摘するように、これはGNU拡張子です)。ただし、改行を含むファイル名には対応していません。これらを処理するには、もう少し複雑なアプローチが必要です。

FWIW、bashのreadコマンドは文字単位でデータを読み取るのに対し、xargsは入力をより効率的に読み取るため、このアプローチはwhile readループよりも多少高速です。また、xargsgrepコマンドを必要な回数だけ呼び出すだけで、各呼び出しは複数のファイル名を受け取ります。これは、ファイルごとにgrepを呼び出すよりも効率的です。名前。

詳細は xargs man page とxargs info pageを参照してください。

7
PM 2Ring

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' {}
3
Xen2050

Forも実行できますが、Orionの例が最も簡単です。

for i in $(cat files.txt); do grep -i 'foo' $i ; done

(files.txtにリストされている各ファイルに対して、grepコマンドを実行します。)

1
Michael