linux
概要
複数のファイルをまとめて処理したり、ファイルの各行を処理するのをコマンド一つで済ませたいことがたまにある。
もちろんシェルスクリプトにもfor文があるのでそれを使う手もあるが、for文をコマンド内で1行にまとめようと思うとなかなか骨が折れる。
そんなときのためにあるのが
xargs
(エックスアーグズ)コマンドだ。
xargsは引数を各行に分解して、それぞれに別個にコマンド適用をしてくれるコマンドだ。
主要なオプション:
- -a [file]: 標準入力でなくファイルから読み込む
- -d [char]: 入力の区切り文字を指定、デフォルトは改行
- -I [string]: プレースホルダを指定、この文字列を入力で置き換えることでコマンドを組み上げてくれる。慣例的には"{}"にする。
- -t: 組み上げたコマンドを実行前に出力(注意:実行もする)デバッグに便利
基本の使い方
# 実験用ファイルをあらかじめ3つ作っておいた $ ls aaa bbb ccc $ cat aaa a $ cat bbb b $ cat ccc c # ファイルをまとめてcat $ ls | xargs -t -I{} cat {} ; cat aaa a cat bbb b cat ccc c $ ls | xargs -I{} cat {} ; a b c
応用例
変更日時順にtop100のファイルをコピー
$ ls -t | head -n 100 | xargs -I{} cp {} bak/{}
sedと組み合わせてファイル名もいじる;
sh -c
によるコマンド実行で、xargsが成形したコマンドを走らせればよい。最初はバッククォートでできると思ったのだが、評価順序の問題でうまくいかなかった。
$ ls ccc ddd.d $ ls | xargs -t -I{} sh -c 'echo {} | sed "s/\./_/"' sh -c echo ccc | sed "s/\./_/" ccc sh -c echo ddd.d | sed "s/\./_/" ddd_d # 失敗例:バッククォートはxargs実行前に評価されてしまう $ ls | xargs -t -I{} `echo {} | sed "s/\./_/"` {} xargs: {}: Permission denied # 失敗例:evalは権限上実行できないようになっているようだ $ ls | xargs -t -I{} eval echo {} | sed "s/\./_/" eval echo aaa xargs: eval: Permission denied
余談
xargsの名前は"eXecute ARGumentS"から来ていると思われる。manでの説明が
xargs - build and execute command lines from standard inputとなっているからだ。