xargsメモ
xargsはよくfindと組み合わせて一括処理したりするのに使うけど、失敗すると大ダメージを受けるのでお勉強。
プログラムを指定しないとecho
xargsにプログラムを指定しないとechoが使われるのでどんな感じに渡されるのか確認できる。
$ ls -l total 0 -rw-r--r-- 1 pasela staff 0B 1 22 17:11 foo -rw-r--r-- 1 pasela staff 0B 1 22 17:11 bar -rw-r--r-- 1 pasela staff 0B 1 22 17:11 baz $ ls | xargs foo bar baz
NUL(\0)区切りで受ける
xargsはデフォルトではホワイトスペースで区切るので、たとえば"Foo Bar"というような空白を含むファイルがあるときに普通に実行すると残念なことになる。
$ ls -l total 0 -rw-r--r-- 1 pasela staff 0B 1 22 17:11 Foo Bar -rw-r--r-- 1 pasela staff 0B 1 22 17:11 baz $ find . type -f -print | xargs rm rm: ./Foo: No such file or directory rm: Bar: No such file or directory
これはこんな感じの3引数として渡される。
rm "./Foo" "Bar" "baz"
これを避けるにはリストを\0区切りで出力して、受ける方も\0区切りで受けるとよい。
findのほうは-print0を使うと\0区切りで出力してくれ、xargsは-0で入力を\0区切りとして受け取れる。
$ find . type -f -print0 | xargs -0 rm
これはこんな感じの2引数として渡される。
rm "./Foo Bar" "baz"
ちなみにGNU版の場合は-d delimで他にも任意のデリミタを指定することができる。
実行コマンドを表示する
-tを指定すると実行するコマンドを表示してくれる。
$ ls | xargs -t /bin/echo bar baz foo bar baz foo
表示した上で実行もするので、dry run的な確認には使えない。勘違いしないように。
ログとして残したい場合なんかにいいかも?
実行するかどうか確認する
-pを指定するとコマンド実行毎に実行するかどうか確認してくる。yで実行、それ以外でスキップ。
$ ls | xargs -p /bin/echo bar baz foo?...y bar baz foo
入力n行ごとに実行する
-L 数字で指定行数ごとにコマンドを実行させられる。
$ ls | xargs -L 1 -t /bin/echo bar bar /bin/echo baz baz /bin/echo foo foo $ ls | xargs -L 2 -t /bin/echo bar baz bar baz /bin/echo foo foo
引数n個ごとに実行する
-n 数字で指定個数の引数ごとにコマンドを実行させられる。
$ ls | xargs -n 1 -t /bin/echo bar bar /bin/echo baz baz /bin/echo foo foo $ ls | xargs -n 2 -t /bin/echo bar baz bar baz /bin/echo foo foo
ん、-Lとの違いがわからない?
ではこうやって1行の入力にしてみると違いがわかるはず。
$ echo "foo bar baz" | xargs -n 1 -t /bin/echo foo foo /bin/echo bar bar /bin/echo baz baz $ echo "foo bar baz" | xargs -L 1 -t /bin/echo foo bar baz foo bar baz
-nのほうはホワイトスペースで3つに区切られた上で、1つずつ実行されている。
-Lのほうは1行の入力ずつ実行されている。
置換文字列で挿入する
普通はxargsに渡したコマンドの最後にxargsが引数を追加して実行されるが、cpやmvみたいにコマンドラインの途中の位置に挿入して欲しい場合は-I repstrが使える。
普通にやると……
$ ls | xargs -t cp /path/to/dest_dir cp /path/to/dest_dir bar baz foo usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
こんな感じのコマンドラインで実行されてしまうが、-Iを使うと……
$ ls | xargs -I % -t cp % /path/to/dest_dir cp bar /path/to/dest_dir cp baz /path/to/dest_dir cp foo /path/to/dest_dir
このように-Iで指定した文字列のところを置換して処理してくれる。
(BSDの場合)もうちょっと賢く
上記のは見てのように自動的に-L 1として処理されてしまうので効率があまりよくない。
ここはcp bar baz foo /path/to/dest_dirってなってほしいよね?
こういう場合、BSD版なら-J repstrを使うとよい。
$ ls | xargs -J % -t cp % /path/to/dest_dir cp bar baz foo /path/to/dest_dir
GNU coreutilsの場合(2013-03-05追記)
GNU版のcpやmv等の場合、--target-directoryというdestinationを指定するオプションがあるので、-Iを使わずに次のようにすることもできる。
$ ls | xargs -t cp --target-directory=/path/to/dest_dir cp --target-directory=/path/to/dest_dir bar baz foo
通常、引数の最後となるdestinationをオプションで手前に持ってくることができる。
複数プロセスで並列に実行する
-P 数字を使うと指定したプロセス数で並列実行してくれる。デフォルトは1。
例えばこんな感じのURLリストがあったとして……
$ cat urls.txt http://www.google.co.jp/ http://www.yahoo.co.jp/ http://www.goo.ne.jp/
こんな感じで実行すると普通は1つずつ実行される。
$ cat urls.txt | xargs -n 1 -t curl >/dev/null curl http://www.google.co.jp/ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 12352 0 12352 0 0 130k 0 --:--:-- --:--:-- --:--:-- 177k curl http://www.yahoo.co.jp/ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 25694 0 25694 0 0 53247 0 --:--:-- --:--:-- --:--:-- 253k curl http://www.goo.ne.jp/ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 64743 0 64743 0 0 630k 0 --:--:-- --:--:-- --:--:-- 916k
-Pを指定してやるとこれを並列に実行して一気にダウンロードできる。
$ cat urls.txt | xargs -n 1 -P 3 -t curl >/dev/null curl http://www.google.co.jp/ curl http://www.yahoo.co.jp/ curl http://www.goo.ne.jp/ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 12340 0 12340 0 0 127k 0 --:--:-- --:--:-- --:--:-- 191k 100 64796 0 64796 0 0 590k 0 --:--:-- --:--:-- --:--:-- 832k % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 25703 0 25703 0 0 59137 0 --:--:-- --:--:-- --:--:-- 522k