xargsで複数のパラメータに対してプレースホルダを使う
環境
- Ubuntu 22.04
xargsで -n と -I が併用できない問題
xargs
を使う際、-I
オプションを使ってパラメータをプレースホルダに差し込むというのをよくやります。
# テスト用ファイル $ cat data.txt aaaa bbbb cccc dddd # ファイルの各行に対して xargs でコマンド実行 # -I で指定したプレースホルダ @ の場所にパラメータが正しく置換されている $ cat data.txt | xargs -I@ echo "The input is [@]." The input is [aaaa]. The input is [bbbb]. The input is [cccc]. The input is [dddd].
パラメータが1つの場合はこれでいいんですが、-n
オプションで2つ以上のパラメータを使おうとすると -I
が使えないため、すごく困ります。
# xargs -n2 でパラメータ2つずつに対してコマンド実行 # 先に指定した -I@ が無視されて -n2 だけが有効になり、パラメータの置換が行われない $ cat data.txt | xargs -I@ -n2 echo "The inputs are [@]." xargs: warning: options --replace and --max-args/-n are mutually exclusive, ignoring previous --replace value The inputs are [@]. aaaa bbbb The inputs are [@]. cccc dddd
sh -c 経由で実行して回避する
これは xargs
に渡すコマンドを sh -c
経由で実行し、シェルの引数 $1
, $2
, ... を使うことで代替できます。
$ cat data.txt | xargs -n2 sh -c 'echo "The inputs are [$1, $2]."' sh The inputs are [aaaa, bbbb]. The inputs are [cccc, dddd].
xargs
から sh -c 'echo "The inputs are [$1, $2]."' sh aaaa bbbb
のような形で sh
にパラメータが渡されるので、あとは sh
で実行するコマンドの中で $1
, $2
等を好きなように使えばOK、という具合です。
コマンド末尾の sh
は、 $0
として渡されるコマンド名を明示的に指定しているだけです。
今回の場合であればこれを無くして xargs -n2 sh -c 'echo "The inputs are [$0, $1]."'
のようにしてもよいのですが、例えばコマンド内で $@
を使った場合に $0
は除外されるといった扱いの違いもあるので、指定しておくとちょっとだけ安心です。