xargsが一部のコマンドでは機能しますが、他のコマンドでは機能しないのはなぜですか?

xargsが一部のコマンドでは機能しますが、他のコマンドでは機能しないのはなぜですか?

このコマンドを実行すると動作します。

find . -type f -print0 | xargs md5sum

これにより、各ファイルのmd5sumが印刷されます。

しかし、他のコマンドでは、すべてのファイルを単一のコマンド呼び出しに渡すようです。たとえば、この問題があるようですprintf。次の警告が表示echoされますprintf

printf: warning: ignoring excess arguments, starting with ...

echoを使用すると、たとえば、次のコマンドがある場合は1行だけ印刷されます。

find . -type f -print0 | xargs -r0 echo GOT

見つかったすべてのファイルと同じ行に「GOT」が一度だけ印刷されたことがわかります。

echoも組み込まれているからだと思いましたが、/bin/echoを明示的に実行すると同じ動作が発生します。

ちなみに、makeコマンドでも次のような問題が発生しました。

$ echo "a b c" | xargs echo GOT
GOT a b c

変える:

GOT a
GOT b
GOT c

私は何が間違っていましたか?まず、コマンドにプレフィックスを付けてデバッグするのはとても役に立ちましたが、echoそうすることもできません。

編集:コメントで述べたように、実際にはその-execオプションは利用できませんfind。実際には、ソートを含むかなり長いパイプラインがありますが、これは無関係な詳細であるようで、私が得ることができないという事実とは何の関係もありません。より簡単なパイプライン作業。

答え1

標準入力から取得されたすべての内容が追加され、いくつかの区切り文字で区切られたxargs command-argコマンドの単一インスタンスを実行すると考えることができます(デフォルトは例で使用した空白またはNULバイトです)。command-argたとえば、

echo 1 2 3 | xargs something

実行できますsomething 1 2 3。または質問に投稿した例を使用して:

echo "a b c" | xargs echo GOT

走るecho GOT a b c

標準入力から取得した各引数 xargs を使用して新しい command-arg インスタンスを生成するには、-n1 オプションを使用できます。

$ echo "a b c" | xargs -n1 echo GOT
GOT a
GOT b
GOT c

もちろん、いくつかのコマンドは複数の引数を受け入れないので、常に使用する必要があります-n1

xargsを使用する利点は、新しいプロセスを作成するのが高価な作業であるため、複数の引数を使用して単一のプロセスを実行する方が高速です。この回答で行ったいくつかのベンチマークを確認してください。 https://unix.stackexchange.com/a/536023/72304

答え2

最初の回答で述べた「使用」に加えて、-n1シェルには特定のコマンドの組み込みバージョンがあります。コマンドが別のプログラム(たとえば)から呼び出されると、xargsシェルの組み込みバージョンではなく外部プログラムが呼び出されます。

特にprintfBashと他のいくつかのシェルに組み込まれており、Bashの組み込みバージョンはすべての引数を使い果たすのに必要なだけフォーマットを繰り返します。

たとえば、Bashの組み込みバージョンを使用すると、

printf '%s and %s\n' How now brown cow

2行を出力しますが、

/usr/bin/printf '%s and %s\n' How now brown cow

インストールしたバージョンによっては、パラメータが多すぎるという不満がある場合があります。

答え3

一般的に私はそれを避けますxargs

Web で見つかったほとんどの例は脆弱です。環境がコードを書く人の前提と一致しない場合、予期しない方法で中断される可能性があります。

この質問で提供された例にもバグがあります。find...を使用します-print0が、次を使用します。xargs いいえ -0

さらに、ほとんどの用途はxargs不要です。特に とともに使用する場合、 のfind式を使用する方がより安定しており、エラーが発生する可能性が少なくなります。-execfind

与えられた例は次のように置き換えることができます。

find . -type f -exec md5sum {} +

関連情報