web-dev-qa-db-ja.com

xargsはいつ必要ですか?

xargsコマンドは常に私を混乱させます。一般的なルールはありますか?

以下の2つの例を検討してください。

$ \ls | grep Cases | less

「Cases」に一致するファイルを出力しますが、コマンドをtouchに変更するとxargsが必要になります:

$ \ls | grep Cases | touch
touch: missing file operand
Try `touch --help' for more information.

$ \ls | grep Cases | xargs touch
136
Zaid

違いは、ターゲットプログラムが受け入れるデータにあります。

パイプを使用するだけの場合、STDIN(標準入力ストリーム)上のデータを、一度に1行ずつソートできる生データの山として受け取ります。ただし、一部のプログラムは標準入力でコマンドを受け入れません。コマンドの引数にそのコマンドが記述されていることを期待しています。たとえば、touchは、コマンドラインで次のようにファイル名をパラメーターとして受け取ります:touch file1.txt

ファイル名を出力するプログラムがある場合標準出力でを使用したい場合引数としてtouchに使用するには、xargsを使用する必要がありますこれは、STDINストリームデータを読み取り、各行をコマンドのスペース区切りの引数に変換します。

これら2つは同等です。

# touch file1.txt
# echo file1.txt | xargs touch

それが何をしていて、なぜそれが必要であるかを正確に知らない限り、xargsを使わないでください。変換を強制するためにxargsを使用するよりも良い方法がある場合がよくあります。変換プロセスには、エスケープやWordの拡張などの潜在的な落とし穴もあります。

146
Caleb

すでに提供されている答えを拡張するために、xargsは、今日のマルチコアおよび分散コンピューティング環境でますます重要になっている1つの優れた機能を実行できます。ジョブを並列処理できます。

例えば:

$ find . -type f -name '*.wav' -print0 |xargs -0 -P 3 -n 1 flac -V8

* .wav => * .flacをエンコードし、3つのプロセスを同時に使用します(-P 3)。

73
amphetamachine

xargsは、stdinにファイルパスのリストがあり、それらを使って何かしたい場合に特に便利です。例えば:

$ git ls-files "*.tex" | xargs -n 1 sed -i "s/color/colour/g"

このステップを段階的に検討してみましょう:

$ git ls-files "*.tex"
tex/ch1/intro.tex
tex/ch1/motivation.tex
....

つまり、入力は何かしたいパスのリストです。

Xargsがこれらのパスで何を行うかを調べるには、次のように、コマンドの前にechoを追加するのがいいでしょう。

$ git ls-files "*.tex" | xargs -n 1 echo sed -i "s/color/colour/g"
sed -i "s/color/colour/g" tex/ch1/intro.tex
sed -i "s/color/colour/g" tex/ch1/motivation.tex
....

-n 1引数は、xargsに各行を独自のコマンドに変換させます。 sed -i "s/color/colour/g"コマンドは、指定されたファイルのすべてのcolorcolourに置き換えます。

これは、パスにスペースがない場合にのみ機能することに注意してください。その場合、-0フラグを渡して、xargsへの入力としてnullで終了するパスを使用する必要があります。使用例は次のとおりです。

$ git ls-files -z "*.tex" | xargs -0 -n 1 sed -i "s/color/colour/g"

これは上記で説明したものと同じですが、パスの1つにスペースがある場合にも機能します。

これは、findlocateなどの出力としてファイル名を生成するすべてのコマンドで機能します。ただし、gitリポジトリで大量のファイルを使用している場合は、次のようにgit grep -lではなくgit ls-filesを使用する方が効率的です。

$ git grep -l "color" "*.tex" | xargs -n 1 sed -i "s/color/colour/g"

git grep -l "color" "*.tex"コマンドは、 "color"という語句を含む "* .tex"ファイルのリストを表示します。

24

あなたの例では、xargsがあなたがしたいことを正確かつ安全に行うので、findを使用する必要はまったくありません。

findを使用して正確に何をしたいですか:

find -maxdepth 1 -name '*Cases*' -exec touch {} +

この例の-maxdepth 1は、現在のディレクトリのみを検索することを意味し、サブディレクトリには移動しません。デフォルトでは、findはmaxdepthで制約しない限り、すべてのサブディレクトリ(たいていはこれが必要です)を検索します。 {}は、その場所で置き換えられるファイルの名前であり、+は2つのコマンド終了マーカーの1つであり、もう1つは;です。それらの違いは、;は各ファイルに対して一度に1つのコマンドを実行することを意味し、+はすべてのファイルに対して一度にコマンドを実行することを意味します。ただし、シェルはおそらく;自体を解釈しようとするため、\;または';'でエスケープする必要があることに注意してください。はい、findには、このような小さな問題がいくつかありますが、その力はそれを補う以上のものです。

findxargsはどちらも最初は覚えるのが難しいです。 xargsを学習するには、-pまたは--interactiveオプションを使用してみてください。実行しようとしているコマンドが表示され、実行するかどうかを確認するメッセージが表示されます。

同様に、findを使用すると、-okの代わりに-execを使用して、コマンドを実行するかどうかを確認できます。

ただし、findが必要なすべてを実行できない場合があり、xargsが登場します。-execコマンドは、表示される{}のインスタンスを1つだけ受け入れるため、 find -type f -exec cp {} {}.bak \;でエラーが発生するため、代わりに次のようにできます:find -type f -print0 | xargs -0 -l1 -IX cp X X.bak

GNU Findutilsマニュアルコマンドの実行 について詳しく学ぶことができます。

また、ファイルを処理しているときに、-0または--nullオプションを一緒に使用しない限り、findで問題を引き起こすスペースやその他の文字に遭遇するため、xargsが安全にあなたが望むことを行うことも述べました空白の代わりにヌル文字で終了する入力項目を生成するもので。

4
aculich

xargsfindsortduuniqPerlおよび他のいくつかとともに)は、 「STDINにはNUL(0x00)バイトで区切られたファイルのリストがあります」と言うコマンドラインスイッチ。これにより、スペースやその他の面白い文字を含むファイル名を簡単に処理できます。ファイル名にはNULは含まれません。

1
waltinator