xargsはいつ必要ですか?


134

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

回答:


143

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

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

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

これら2つのことは同等です。

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

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


2
警告は私に少しひもを感じます。コマンドライン(xargsおよび$(...))にストリームを取得する2つの一般的なオプションのうち、xargsはコマンド置換よりもはるかに安全です。そして、改行を含む正当なファイル名に出くわしたことを思い出せません。エスケープと単語拡張の落とし穴は、xargsではなくコマンド置換の問題ではありませんか?
CAMH

6
@camh:両方とも潜在的な落とし穴です。シェルでは、ファイル名がスペース、タブ、改行で分割されることを心配する必要があります。xargsでは、改行だけを心配する必要があります。xargsでは、出力が適切にフォーマットされている場合、代わりにNUL文字で単語/ファイル名を分割できます(xargs -0)。これはと組み合わせて使用​​すると便利ですfind -print0
ケンブルーム

xargsスペースで区切られた引数を使用してシェル経由でプログラムを呼び出しますか、それとも実際に引数リストを内部で構築しますか(例:execv/ で使用するためexecp)?
確実に

1
内部で構築し、execvpを使用するため、安全です。また、GNU xargs(Linuxおよび他のいくつかで使用される)を使用して、区切り文字として改行を指定できます-d \nが、BSD xargs(OSXなど)はこのオプションをサポートしていないようです。
ふわふわ

72

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

例えば:

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

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


ワオ。50GiBのWAVでまったく同じこと(OGGを使用することを除く)を行っていた1週間前にこれを知っていたはずです。:)
アロイスマーダル

findが持っている-execパラメータを使用しないのはなぜですか?
エフゲニー

3
@Evgeny -execパラメーターはジョブを並列処理しません。
amphetamachine

-0引数をxargsNULL入力文字の区切り文字と見なすことに注意してくださいfind -print0NULLで区切られたアイテムを出力します。これは、スペース、引用符、またはその他の特殊文字が含まれる可能性のあるファイル名には最適です。
ダンダスカレスク

24

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フラグを渡すことにより、nargで終了したパスをxargsへの入力として使用する必要があります。使用例は次のとおりです。

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

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

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

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

このgit grep -l "color" "*.tex"コマンドは、フレーズ「color」を含む「* .tex」ファイルのリストを提供します。


1
確かに、しかし、あなたはこれを学んだ場合は、必要があるにも学ぶなぜ見つけるの出力悪い習慣をループされますか?
ワイルドカード

6

最初の引数は、違いを非常によく示しています。

\ls | grep Cases | lesslsおよびで作成されたファイル名のリストを参照できますgrep。それらがファイル名であることは問題ではなく、単なるテキストです。

\ls | grep Cases | xargs lessコマンドの最初の部分で作成された名前のファイルを参照できます。xargs入力としてファイル名のリストを受け取り、コマンドラインでコマンドを受け取り、コマンドラインでファイル名を使用しコマンドを実行します。

の使用を検討する際xargsには、入力が奇妙な方法でフォーマットされることを想定してください:ホワイトスペース区切り、with \'および"引用に使用されます(引用\内では特別ではないため、異常な方法で)。xargsファイル名に空白やが含まれていない場合にのみ使用してください\'"


@Gilles: スペースの問題を回避xargsする-0, --nullオプションがあります(私はあなたからそれを学んだ可能性が非常に高いです:)。したがって、あなたはノーオプションxargコールを参照していると思いますが、引用への参照に戸惑っています。それに関するリンクや例はありますか?..(ps。| xargs lessは便利な「トリック」+1 ..ありがとう..
Peter.O

4

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

正確に使用したいものfindは次のとおりです。

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

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

両方ともfindxargs最初は学ぶのが難しいです。学習しやすくするために、xargs実行しようとしているコマンドを表示する-por --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マニュアルRun Commandsの詳細を学ぶことができます

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



@Wildcardファイル名にスペースや文字が含まれる、'またはなどの"問題が発生する可能性がありますが、findこれらのケースは問題なく処理されます。
aculich 16

はい、知っています。リンクされた質問への私の答えを参照しください。おそらく、その質問を上記のコメントの文に言い換えるか、その前に「See the question ...」というフレーズを追加する必要がありました。:D
ワイルドカード

1

xargs(と一緒にfindsortduuniqperlおよびいくつかの他)「STDINはNUL(0×00)バイトで区切られ、ファイルのリストを持っている」と言って、コマンドラインスイッチを受け付けます。これにより、スペースやその他の面白い文字を含むファイル名を簡単に処理できます。ファイル名にはNULは含まれません。


2
「ファイル名にヌルを含めることはできません」という意味だと思います。
amphetamachine
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.