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が正確に何をしているのかまだ苦労しているので、どんな助けでも大歓迎です!
$ 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のコメントで示唆されているように、これらの追加の説明ポイントを追加
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 | grep
はfind
が出力するファイル名のリストに対してパターンマッチングを行います。
したがって、その時点で、find -name stdlib.h
を実行することもできます。もちろん、-name '*.c' -name stdlib.h
を使用すると、これらのパターンは両方とも一致することができず、findのデフォルトの動作はルールをANDで結合するため、出力は得られません。
パイプラインの一部が生成する出力を確認するには、プロセスの任意の時点でless
を置き換えます。
さらに読む: http://mywiki.wooledge.org/BashFAQ には素晴らしいものがあります。
一般的に、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
とともに使用するとメリットがあります。
xargs
は、ファイルのリストに基づいて(通常)コマンドライン引数を自動生成するために使用されます。
したがって、次のxargs
コマンドを使用する代わりにいくつかの方法を検討します。
find . -name '*.c' -print0 | xargs -0 grep 'stdlib.h'
もともと他の回答で言及されていなかった他のオプションの代わりにそれを使用する理由がいくつかあります。
find . -name '*.c' -exec grep 'stdlib.h' {}\;
は、ファイルごとに1つのgrep
プロセスを生成します。これは一般に悪い習慣と見なされ、多くのファイルが見つかった場合、システムに大きな負荷をかける可能性があります。grep 'stdlib.h' $(find . -name '*.c')
操作の出力がシェルのコマンドラインの最大長を超えるため、$(...)
コマンドは失敗する可能性があります。他の回答で述べたように、このシナリオでfind
に-print0
引数を使用し、xargsに-0
引数を使用する理由は、特定の文字(引用符、スペース、改行さえも)まだ正しく処理されます。