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
違いは、ターゲットプログラムが受け入れるデータにあります。
パイプを使用するだけの場合、STDIN(標準入力ストリーム)上のデータを、一度に1行ずつソートできる生データの山として受け取ります。ただし、一部のプログラムは標準入力でコマンドを受け入れません。コマンドの引数にそのコマンドが記述されていることを期待しています。たとえば、touch
は、コマンドラインで次のようにファイル名をパラメーターとして受け取ります:touch file1.txt
。
ファイル名を出力するプログラムがある場合標準出力でを使用したい場合引数としてをtouch
に使用するには、xargs
を使用する必要がありますこれは、STDINストリームデータを読み取り、各行をコマンドのスペース区切りの引数に変換します。
これら2つは同等です。
# touch file1.txt
# echo file1.txt | xargs touch
それが何をしていて、なぜそれが必要であるかを正確に知らない限り、xargs
を使わないでください。変換を強制するためにxargs
を使用するよりも良い方法がある場合がよくあります。変換プロセスには、エスケープやWordの拡張などの潜在的な落とし穴もあります。
すでに提供されている答えを拡張するために、xargs
は、今日のマルチコアおよび分散コンピューティング環境でますます重要になっている1つの優れた機能を実行できます。ジョブを並列処理できます。
例えば:
$ find . -type f -name '*.wav' -print0 |xargs -0 -P 3 -n 1 flac -V8
* .wav => * .flacをエンコードし、3つのプロセスを同時に使用します(-P 3
)。
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"
コマンドは、指定されたファイルのすべてのcolor
をcolour
に置き換えます。
これは、パスにスペースがない場合にのみ機能することに注意してください。その場合、-0
フラグを渡して、xargsへの入力としてnullで終了するパスを使用する必要があります。使用例は次のとおりです。
$ git ls-files -z "*.tex" | xargs -0 -n 1 sed -i "s/color/colour/g"
これは上記で説明したものと同じですが、パスの1つにスペースがある場合にも機能します。
これは、find
やlocate
などの出力としてファイル名を生成するすべてのコマンドで機能します。ただし、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"ファイルのリストを表示します。
あなたの例では、xargs
があなたがしたいことを正確かつ安全に行うので、find
を使用する必要はまったくありません。
find
を使用して正確に何をしたいですか:
find -maxdepth 1 -name '*Cases*' -exec touch {} +
この例の-maxdepth 1
は、現在のディレクトリのみを検索することを意味し、サブディレクトリには移動しません。デフォルトでは、findはmaxdepthで制約しない限り、すべてのサブディレクトリ(たいていはこれが必要です)を検索します。 {}
は、その場所で置き換えられるファイルの名前であり、+
は2つのコマンド終了マーカーの1つであり、もう1つは;
です。それらの違いは、;
は各ファイルに対して一度に1つのコマンドを実行することを意味し、+
はすべてのファイルに対して一度にコマンドを実行することを意味します。ただし、シェルはおそらく;
自体を解釈しようとするため、\;
または';'
でエスケープする必要があることに注意してください。はい、find
には、このような小さな問題がいくつかありますが、その力はそれを補う以上のものです。
find
とxargs
はどちらも最初は覚えるのが難しいです。 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
が安全にあなたが望むことを行うことも述べました空白の代わりにヌル文字で終了する入力項目を生成するもので。
xargs
(find
、sort
、du
、uniq
、Perl
および他のいくつかとともに)は、 「STDINにはNUL(0x00)バイトで区切られたファイルのリストがあります」と言うコマンドラインスイッチ。これにより、スペースやその他の面白い文字を含むファイル名を簡単に処理できます。ファイル名にはNULは含まれません。