web-dev-qa-db-ja.com

「xargs grep」は何をしますか?

grepコマンドを知っており、xargsの機能について学んでいるので、 this ページを読んで、xargsコマンドの使用方法の例を示します。

最後の例、例10に混乱しています。「xargsコマンドはgrepコマンドを実行して、文字列「stdlib.h」を含むすべてのファイルを検索します(findコマンドで提供されたファイル)」

$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...

ただし、単に使用することとの違いは何ですか

$ find . -name '*.c' | grep 'stdlib.h'

明らかに、私はまだxargsが正確に何をしているのかまだ苦労しているので、どんな助けでも大歓迎です!

24
AlphaOmega
$ find . -name '*.c' | grep 'stdlib.h'

これは、出力(stdout)*をfindから(stdin of)* grep 'stdlib.h'as textにパイプします(つまり、ファイル名はテキストとして扱われます) 。 grepは通常の処理を行い、このテキスト(パターンを含むファイル名)で一致する行を見つけます。ファイルの内容は読み取られません。

$ find . -name '*.c' | xargs grep 'stdlib.h'

これは、commandgrep 'stdlib.h'を構成し、findからの各結果は引数です。したがって、これは一致を探します内部findで見つかった各ファイル(xargsが考えられます)その標準入力を与えられたコマンドの引数に変換する)*

Findコマンドで-type fを使用します。そうしないと、一致するディレクトリに対してgrepからエラーが発生します。また、ファイル名にスペースが含まれていると、xargsがひどく破損するため、-print0およびxargs -0を追加してnullセパレータを使用すると、より信頼性の高い結果が得られます。

find . -type f -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

* @ catのコメントで示唆されているように、これらの追加の説明ポイントを追加

29
Zanna

xargsは標準入力を取り、それをコマンドライン引数に変換します。

find . -name '*.c' | xargs grep 'stdlib.h'は非常に似ています

grep 'stdlib.h' $(find . -name '*.c')  # UNSAFE, DON'T USE

ファイル名のリストが単一のコマンドラインに対して長すぎない限り、同じ結果が得られます。 (Linuxは1つのコマンドラインでメガバイトのテキストをサポートしているため、通常はxargsは必要ありません。)


しかし、ファイル名にスペースが含まれていると壊れるので、これらは両方とも悪いです。代わりに、find -print0 | xargs -0は動作しますが、動作します

find . -name '*.c' -exec grep 'stdlib.h' {} +

それはファイル名をどこにもパイプしません:findはそれらを大きなコマンドラインにまとめ、grepを直接実行します。

\;の代わりに+はファイルごとにgrepを個別に実行しますが、これは非常に低速です。しないでください。ただし、+はGNU拡張であるため、GNUを見つけることができない場合、これを効率的に行うにはxargsが必要です。


xargsを省略すると、find | grepfindが出力するファイル名のリストに対してパターンマッチングを行います。

したがって、その時点で、find -name stdlib.hを実行することもできます。もちろん、-name '*.c' -name stdlib.hを使用すると、これらのパターンは両方とも一致することができず、findのデフォルトの動作はルールをANDで結合するため、出力は得られません。

パイプラインの一部が生成する出力を確認するには、プロセスの任意の時点でlessを置き換えます。


さらに読む: http://mywiki.wooledge.org/BashFAQ には素晴らしいものがあります。

6
Peter Cordes

一般的に、xargsは、あるコマンドから別のコマンド(|)に何かを(シンボルCommand1 | Command2で)パイプする場合に使用されますが、最初のコマンドからの出力はそうではありません2番目のコマンドの入力として正しく受信されました。

これは通常、2番目のコマンドが標準入力(stdin)を介したデータ入力を正しく処理しない場合に発生します(例:入力としての複数の行、行の設定方法、入力として使用される文字、入力としての複数のパラメーター、受信したデータ型入力など)。簡単な例を示すには、次をテストします。

例1:

ls | echo-echoは受け取った入力の処理方法を知らないため、これは何もしません。この場合、xargsを使用すると、echoで正しく処理できる方法で入力を処理します(例:1行の情報として)

ls | xargs echo-これは、lsからのすべての情報を1行で出力します

例2:

Goというフォルダー内に複数のgoLangファイルがあるとします。私は次のようなものでそれらを探します:

find go -name *.go -type f | echo-ただし、そこにパイプ記号があり、最後にechoがある場合、機能しません。

find go -name *.go -type f | xargs echo-ここではxargsのおかげで機能しますが、findコマンドからの各応答が1行で必要な場合は、次のようにします。

find go -name *.go -type f | xargs -0 echo-この場合、findからの同じ出力がechoによって表示されます。

cp, echo, rm, lessなどの入力を処理するためのより良い方法を必要とするコマンドは、xargsとともに使用するとメリットがあります。

5
Luis Alvarado

xargsは、ファイルのリストに基づいて(通常)コマンドライン引数を自動生成するために使用されます。

したがって、次のxargsコマンドを使用する代わりにいくつかの方法を検討します。

find . -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

もともと他の回答で言及されていなかった他のオプションの代わりにそれを使用する理由がいくつかあります。

  1. find . -name '*.c' -exec grep 'stdlib.h' {}\;は、ファイルごとに1つのgrepプロセスを生成します。これは一般に悪い習慣と見なされ、多くのファイルが見つかった場合、システムに大きな負荷をかける可能性があります。
  2. 多数のファイルがある場合、grep 'stdlib.h' $(find . -name '*.c')操作の出力がシェルのコマンドラインの最大長を超えるため、$(...)コマンドは失敗する可能性があります。

他の回答で述べたように、このシナリオでfind-print0引数を使用し、xargsに-0引数を使用する理由は、特定の文字(引用符、スペース、改行さえも)まだ正しく処理されます。

4
Michael Firth