xargsのオプション無し、-Iオプション、-0オプションの挙動に関する勘違い

  • 61
    Like
  • 2
    Comment
More than 1 year has passed since last update.

概要

xargsの挙動について激しく勘違いしててはまったので、どう勘違いしてて実際どうなのかをまとめる。

オプション無し勘違い

今まで

$ echo 'a b c' | xargs echo

と書いたら、

$ echo a
$ echo b
$ echo c

と挙動が同じになると思ってた。本当は

$ echo a b c

になるのね。もっと言うと

$ echo "a b\nc\td     e" | xargs echo

$ echo a b c d e

と同じになるのね。このデフォルトのデリミタはスペース、タブ、改行、EOF。

-I オプションの勘違い

xargs-Iオプションってあるじゃないですか。これって、

$ echo "a b\nc\td     e" | xargs -I{} echo {}

ってやると、

$ echo "a b\nc\td     e" | xargs echo

と同じだと思ってた。実際に実行させてみると

$ echo "a b\nc\td     e" | xargs -I{} echo {}
a b
c d e
$ echo "a b\nc\td     e" | xargs echo
a b c d e

違う。
manを見ると、確かに改行ごとにxargsの後ろのコマンドを実行する、と書いてある。つまり、

$ echo "a b\nc\td     e" | xargs -I{} echo {}

$ echo "a b" | xargs echo
$ echo "c\td     e" | xargs echo

とほぼ等価である。

-0オプションの勘違い

-0オプションはデリミタをヌル文字にするオプション。なので、

$ echo "a b\nc\td     e" | xargs -I{} echo {}

と、上記コマンドの\nをヌル文字にして-0オプションを付けた

$ echo "a b\0c\td     e" | xargs -0 -I{} echo {}

は同じ、だと思っていた。が、違う。

$ echo "a b\nc\td     e" | xargs -I{} echo {}
a b
c d e
$ echo "a b\0c\td     e" | xargs -0 -I{} echo {}
a b
c   d     e

つまり、

$ echo "a b\nc\td     e" | xargs -I{} echo {}

$ echo "a b" | xargs echo
$ echo "c\td     e" | xargs echo

とほぼ等価で(これは前項のとおり)、

$ echo "a b\0c\td     e" | xargs -0 -I{} echo {}

$ echo "a b"
$ echo "c\td     e"

とほぼ等価になる。
後ろのxargs echoが消えたわけではなく、xargsに渡される文字列の空白文字が全部半角スペースに変換されずにそのままechoに渡される(例のコマンドにechoを2回使ってるせいで分かりづらいけど直すのめんどくさいからこのままで...)

あんまり関係ないけど

xargs って第一引数省略するとechoになるのね
つまり

echo "a b\nc\td     e" | xargs echo

echo "a b\nc\td     e" | xargs

と等価。