XARGS(1) | General Commands Manual | XARGS(1) |
xargs - 標準入力を読み込んでコマンドラインを作成し、それを実行する
xargs [-0prtx] [-E eof-str] [-e[eof-str]] [--eof[=eof-str]] [--null] [-d delimiter] [--delimiter delimiter] [-I replace-str] [-i[replace-str]] [--replace[=replace-str]] [-l[max-lines]] [-L max-lines] [--max-lines[=max-lines]] [-n max-args] [--max-args=max-args] [-s max-chars] [--max-chars=max-chars] [-P max-procs] [--max-procs=max-procs] [--process-slot-var=name] [--interactive] [--verbose] [--exit] [--no-run-if-empty] [--arg-file=file] [--show-limits] [--version] [--help] [command [initial-arguments]]
[訳注]: 見やすくするために、整理して単純化すると:
xargs [options] [command [initial-arguments]]
このマニュアルページは、GNU 版 xargs の使用法を説明している。 xargs は、標準入力から空白や改行で区切られた一連の項目を読み込み (空白はダブルクォート、シングルクォート、バックスラッシュによって保護できる)、 それを引き数にして、指定した command を 1 回以上実行する (デフォルトのコマンドは /bin/echo である)。このとき、ユーザが command に対して指定した引き数 (上記書式の initial-arguments) があれば、 標準入力から読み込んだ一連の項目は、その後ろに追加される。 標準入力における空行は無視する。
command のコマンドラインは、(-n や -L オプションが使用されていない場合は) システムが定めているコマンドラインの長さの限界に達するまで、長いものが作成される。 そして、指定された command が、入力項目のリストを一つ残らず処理するのに必要な回数だけ、呼び出される。 だから、おおむね、command が呼び出される回数は、入力項目の数よりも、ずっと少なくてすむわけだ。 このことは、たいていの場合、パフォーマンスを著しく向上させることになる。 なお、コマンドの中には、都合がよいことに、並列的に実行できるものもある。-P オプションを参照していただきたい。
Unix ではファイル名に空白や改行を含むことが可能なので、 こうしたデフォルトの動作は、しばしば問題を引き起こす。空白や改行を含むファイル名は、 xargs によって適切に処理されないのだ。そうした状況では、-0 オプションを使用した方がよい。そうすれば、その手の問題を回避することができる。 なお、-0 オプションを使う場合は、xargs の入力を生成するプログラムの方でも、区切りの指標に必ずヌル文字を使うようにする必要がある。 たとえば、そのプログラムが GNU find ならば、-print0 オプションでそれが可能だ。
指定したコマンドの実行が終了ステータス 255 で終了することがあれば、 xargs は即座に停止して、それ以上入力を読み込まない。 また、このとき、エラーメッセージを標準エラーに表示する。
$ echo -e "AAA BBB\nCCC\nDDD" |xargs -I{} echo {} is {} AAA BBB is AAA BBB CCC is CCC DDD is DDD
入力項目を区切っているデリミタは改行だけであり、空白は項目の区切りとして機能していないのがお分かりになるだろう。 別の言い方をすると、-I では、各行は 1 行全体が事実上クォートされてコマンドに渡される (注意: -L 1 にそんな作用はない)。 従って、-I オプションを使えば、空白を含むファイル名を処理できるということになる。 たとえば、カレントディレクトリに "nospace" と "have space" というファイルがあるとしよう。
$ ls |xargs file have: cannot open `have' (No such file or directory) space: cannot open `space' (No such file or directory) nospace: ASCII text $ ls |xargs -L1 file have: cannot open `have' (No such file or directory) space: cannot open `space' (No such file or directory) nospace: ASCII text $ ls |xargs -I{} file {} have space: UTF-8 Unicode text nospace: ASCII text
$ echo AAA BBB CCC |xargs -L1 echo "line: " line: AAA BBB CCC $ echo -e "AAA\nBBB\nCCC" |xargs -L1 echo "line: " line: AAA line: BBB line: CCC $ echo -e "AAA \nBBB\nCCC" |xargs -L1 echo "line: " line: AAA BBB line: CCC
注意していただきたいが、共有リソースに対する並列アクセスをきちんと管理するのは、呼び出されるプロセス側の問題だ。 たとえば、複数のプロセスが標準出力に書き出そうとした場合、出力は不定の順番で生成されることになる (だから,混じり合ってしまう可能性が高い)。そうならないためには、プロセス同士が何らかの形で協力し合う必要がある。 ロッキング・スキームのようなものを使うのは、そうした問題を避けるための一方法である。 ただ、一般に、ロッキング・スキームの使用は、適切な出力を保証してはくれるものの、パフォーマンスを低下させることになる。 パフォーマンスが落ちるのが嫌ならば、単純に各プロセスがそれぞれ別の出力ファイルを作るように (あるいは、別のリソースを使うように) すればよい。
find /tmp -name core -type f -print | xargs /bin/rm -f
/tmp ディレクトリ以下に core という名前のファイルを捜して、それを消去する。 改行や空白を含むファイル名があると、正しく動作しないので、注意すること。
find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
/tmp
ディレクトリ以下に
core
という名前のファイルを捜して、それを消去する。
ファイル名の処理に当たっては、ファイル名やディレクトリ名に空白や改行が含まれていても、適切に扱われるようにしている。
find /tmp -depth -name core -type f -delete
/tmp
ディレクトリ以下に
core
という名前のファイルを捜して、それを消去する。
上の例よりもこちらの方が効率的である
(なぜなら、 rm
を実行するために
fork(2) と exec(2)
を使わないですむし、そもそも、
xargs
のプロセスを必要としないから)。
cut -d: -f1 < /etc/passwd | sort | xargs echoシステムの全ユーザを列挙した簡潔なリストを生成する (訳注: 要するに、改行ではなく、空白で区切られたユーザ名のリストを作るということ)。
xargs sh -c 'emacs "$@" < /dev/tty' emacsxargs の標準入力からファイルのリストを受け取り、Emacs を必要なだけ次々と実行して、ファイルを編集する。この例は BSD の -o オプションと同じことを実現するが、こちらの方が柔軟性があり、多くのシステムで利用できる。
xargs の終了ステータスは以下のとおりである。
0 成功した。 123 指定したコマンドの実行が 1-125 のステータスで終了した。 124 指定したコマンドが 255 のステータスで終了した。 125 指定したコマンドがシグナルによって kill された。 126 指定したコマンドが実行できない。 127 指定したコマンドが見つからない。 1 上記以外のエラーが起きた。
128 以上の終了ステータスは、致命的なシグナルのせいでプログラムが止まったことを示すために、シェルが使用している。
GNU xargs version 4.2.9 以来、ファイルの論理的な終端を示す指標 (a logical end-of-file marker) を持たないのが、xargs のデフォルトになっている。このことは POSIX (IEEE Std 1003.1, 2004 Edition) で認められている。
-l や -i オプションは 1997 年版の POSIX 規格には存在するが、 2004 年版の POSIX 規格には存在しない。従って、それぞれ -L や -I の方を使うべきである。
POSIX 規格は、実装に当たって、exec 関数に対する引き数のサイズに上限を設けることを認めている。 そして、その上限は、環境のサイズも含めて、少なくとも 4096 バイトあればよいことになっている。 移植性のあるスクリプトを書こうと思ったら、これより大きいサイズを当てにしてはいけない。 もっとも、実際の上限がそんなに小さい実装に、筆者は出会ったことがないけれど。 --show-limits オプションを使えば、使用中のシステムで有効な実際の上限を知ることができる。
find(1), locate(1), locatedb(5), updatedb(1), fork(2), execvp(3), kill(1), signal(7),
xargs については、充実した関連文書が Texinfo マニュアルの形で保守されている。 info と xargs プログラムが、御使用のサイトできちんとインストールされているならば、 info xargs とコマンドを打ち込むことで、詳細なマニュアルが読めるはずだ。
-L オプションと -I オプションを組み合わせても、うまく行かない。 組み合わせて使えた方がよいのかもしれないが。
xargs を安全に使うことは不可能である。なぜなら、入力されるファイル名のリストを生成する時間と xargs が実行するコマンドがそれを使用する時間との間には、必ず時間差があるからだ。 もし、他のユーザがシステムにアクセスすることができれば、 そのユーザはこの時間の隙間にファイルシステムを操作して、xargs が実行するコマンドの動作を、こちらが意図していないファイルに無理矢理向けることができる。 この問題や、これに関連する問題については、 findutils に含まれる Texinfo 文書の「Security Considerations」という章でもっと細かく論じているので、 そちらを参照していただきたい。なお、find の -execdir オプションは、より安全な方法として xargs の代わりに使用できることが多い。
-I オプションを使うと、標準入力から読み込まれた各行が内部的にバッファされる。 それは、-I オプションを付けて使ったとき、xargs が受け入れる入力行 1 行の長さに上限があるということだ。この制限を回避するには、-s オプションを使って、xargs が使用するバッファ空間のサイズを増やしてやればよい。 さらに、xargs をもう一つ実行すれば、長すぎる行の出現を確実に避けることができる。たとえば、
somecommand | xargs -s 50000 echo | xargs -I '{}' -s 100000 rm '{}'
この例では、xargs の最初の実行には、入力行の長さの上限がない。 -I オプションを使っていないからである。 xargs の二番目の実行には、そうした上限があるが、処理できる以上の長さの行に絶対に出会わないようになっている。 これが理想的な解決法だというのではない。むしろ、 -I オプションによって入力行の長さに上限ができない方がよいのであり、 だからこそ、この問題を「バグ」セクションで論じているのである。 なお、この問題は find(1) の出力では起きない。find は 1 行に 1 ファイル名しか出力しないからだ。
バグ報告の最善の方法は、http://savannah.gnu.org/bugs/?group=findutils にある書式を使用することである。そうすれば、問題解決の進行状態を追うことができるからだ。 xargs(1) や findutils パッケージ全般についてのその他のご意見は、 bug-findutils メーリングリストにお出しになればよい。 メーリングリストに参加するには、bug-findutils-request@gnu.org 宛に E メールを送っていただきたい。
この翻訳は findutils-4.6.0 所収の xargs.1 の翻訳である。 お手元の findutils は、もっと新しいバージョン、たとえば 4.7.0-git になっているかもしれない。だが、4.7.0 は開発中の版なので、manpage も変化し続けており、現時点で最新の 4.7.0 のマニュアルを翻訳しても、お手元の英語マニュアルとは内容が微妙に違うかもしれないのだ。 バージョンが同じ 4.7.0 なのに、それでは紛らわしい。そこで、あえて現在の安定版、4.6.0 のマニュアルを底本にした。
ご参考までに書いておくと、2017/06/09 以降の 4.7.0-git の xargs には、-o (--open-tty) というオプションが追加されている。4.7.0-git の man xargs によれば、「コマンドを実行する前に、子プロセスで標準入力を /dev/tty として再オープンする」というものである。そうした最近のバージョンでは -o オプションを使えば、たとえば "find . -name '*.txt~' | xargs -o rm -i" といったことが可能になるようだ。失敗しても困らないファイルでお試しいただきたい。 (2018/03/03)