概要
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
と等価。