xargs コマンド

ファイル名の一覧を標準入力から受け取って、そのファイル一覧を任意のコマンドに引数として渡すコマンド。ファイル一覧でなくてもなんでもよい。

わかりづらいので、例として、カレントディレクトリの配下にある拡張子が .txt のファイルをすべて削除したいとする。

まずはfindコマンドでリストアップする。

$ find . -name "*.txt"

この結果が以下のようだったとする。

foo.txt
sub/bar.txt

これらを削除するには

$ rm foo.txt sub/bar.txt

を実行すればよいが、findの結果が大量にある場合はrmコマンドを手で書くのは手間なので、 findの結果をそのままrmに渡したい。rmコマンドが標準入力からファイル名を受け取ってくれるならパイプでつなぐだけだが、残念ながらrmにはパラメータで渡す必要がある。こういうときにxargsコマンドを使う。以下のような感じ。

$ find . -name "*.txt" | xargs rm

xargsコマンドは標準入力から受け取ったデータをそのままrmコマンドのパラメータとしてrmを実行する。

ちなみに以下のようにしても同じようなことができる。

$ rm `find . -name "*.txt"`

ただし、この場合findの結果があまりに大量だと、エラーになってしまう。コマンドに渡すパラメータの長さには制限があるからである。制限を超えると自分の環境では Argument list too long というエラーが表示される。

しかし、xargsを使えば、この制限を超える場合に、適度に分割して rm を複数回実行することで自動でこの制限を回避してくれる。

ちなみに、このパラメータの長さの上限値はカーネルに依存し、以下のコマンドでバイト数で確認することができる。

getconf ARG_MAX

この上限値はカーネルソースのexec.cのあたりに実装されていそうだが、よくわからない。

mv に渡す場合は要注意

xargs は、コマンドの最後にファイル名を引数として渡す。 mv コマンドはデフォルトでは、パラメータで渡したファイル名たちの最後のものが移動先になる。なので、移動元のたくさんのファイル名をxargsに渡してmvで移動させるには -t オプションを付けて移動先を明示的に指定する必要がある。

find . -type f | xargs mv -t ~/dst

これで mv コマンドは mv -t ~/dst a.txt b.txt dir/c.txt dir/d.txt として実行され、 ~/dst にテキストファイルたちが移動されることになる。 -t がないと、 mv ~/dst a.txt b.txt dir/c.txt dir/d.txt となり、意図した動作にはならずに dir/d.txt に上書き移動しようとしてしまう。

ただし、-t オプションは環境によってはサポートされていないらしい。

別の使い方として、xargsから移動元ファイル名と移動先ファイル名をペアでmvに渡すやりかたもある。

こんな感じ。

find . -type f | perl -nle 'print "$_\n$_.bak"' | xargs -n2 mv

見つかったファイル一覧を、perlのワンライナーでもとのファイル名とそれに .bak を付けたファイル名のペアにして、 xargs-n2 を付けることで2つずつ mv に渡して、各ファイルをリネームする。

一度にコマンドに渡す引数の最大数を制御するには

-n オプションを使って最大数を設定できる。

例えば、-n 3 とすると、コマンドに最大で3つまでしか引数を渡さず、 4つ以上ある場合はコマンドを複数回実行される。

ディレクトリに a.txt, b.txt, c.txt, test.sh があって、 test.sh が以下の内容とし、

echo "exec: test.sh"
echo "$@"

以下を実行すると、

ls | xargs sh test.sh

以下のように出力される

exec: test.sh
a.txt b.txt c.txt test.sh

-n オプションで最大1に設定すると、

ls | xargs -n 1 sh test.sh

以下のように出力される

exec: test.sh
a.txt
exec: test.sh
b.txt
exec: test.sh
c.txt
exec: test.sh
test.sh

-n の後ろに空白を入れなくてもよい。

ls | xargs -n1 sh test.sh
このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。
スポンサーリンク