bash の似たものシリーズ
初心者が躓きそうなbash で似て紛らわしいものの違いをはっきりさせようとさせるシリーズ。
bash に於ける xargs / for には違いがあるのか?
あります。結構大きな違いが有ります。
それぞれのループの回しかたを復習しておきましょう。
for ループでコマンド結果を回す
for e in some_command ; echo $e; done
xargs パイプでコマンド結果を回す
some_command | xargs -I @ echo @;
この2つの、コマンドの実行には違いが在るのでしょうか。またコマンドの実行の速度には違いが出るでしょうか?
2つの違い
- xargsはサブシェルを起動するので変数の名前空間が違う
- コマンドの終了を待つfor と 終了を待たない xargs
こんかいは、この後者の違いについて着目したいと思います。
毎秒カウントを出力するスクリプトを作ります。
まず、終了に10秒かかるスクリプトを作ります。
このコマンドは、毎秒1回カウント回数を出力します。
10.times.loop.sh
#!/usr/bin/env bash for (( i=0; i<10; i++ )) ; do echo $i; sleep 1 ; done
単体で実行すると、1秒ずつカウントします。
0 # sleep 1 1 # sleep 1 2 .... 9
xargs で実行したとき。
takuya@~$ bash 10.times.loop.sh | xargs -I@ echo xargs @ xargs 0 xargs 1 xargs 2 xargs 3 xargs 4 xargs 5 xargs 6 xargs 7 xargs 8 xargs 9
for で実行したとき。
takuya@~$ for i in $( bash 10.times.loop.sh ) ; do echo for $i; done ; for 0 for 1 for 2 for 3 for 4 for 5 for 6 for 7 for 8 for 9
ブログで書くとおなじみに見えます。
ブログで書くと同じに見えます。が、全然違います。
動画で見てください。
xargs の例
for の例
動作の違い
xargs
xargs は 前のコマンドから出力が出るたびに処理される。
for
for だと、前のコマンドが終了するまで何も出来ない。
for とxargs
それは for はコマンドの実行終了を待って処理しているから。 xargs は出力があるたびに stdin から読み込んで逐次処理をするから。
for i in COMMAND; do echo $i ;done
この場合、for は COMMAND が終了するまでイテレーションの要素数が決まらないので、何も出来ない。
COMMAND | xargs -I @ echo @
この場合、xargs は前のコマンドから受け取って、入力が来たら逐次処理をする。
これは sed などでも同じこと
パイプライン処理の有能さは、非同期に実行できるところにある。
takuya@~$ bash 10.times.loop.sh| sed -e "s/\([0-9]\)/sed \1/" sed 0 sed 1 sed 2 sed 3 sed 4 sed 5 sed 6 sed 7 sed 8 sed 9
もしコレを for で回してしまうと・・・コマンドの終了待ちが出てしまう。
for i in $( bash 10.times.loop.sh ) ; do echo $i | sed -e "s/\([0-9]\)/sed \1/; done ; ## for の引数のコマンドの終了待ちが出る
awk でも同じ
takuya@~$ bash 10.times.loop.sh| awk '{ print gensub(/([0-9])/, "awk \\1",1, $0) } ' awk 0 # 逐次処理される。 awk 1 awk 2 awk 3 awk 4 awk 5 awk 6 awk 7 awk 8 awk 9
gensub は gnu awk の機能名ので osx の bsd awk にはないけど。
まとめ パイライン
このことは、パイプライン処理では、10.times.loop.sh の標準出力と xargs 標準入力を繋いでから起動することに起因する。
パイプライン処理などで、STDIN/STDOUTを接続するときは、接続される側する側の両方を起動して繋いでコマンド実行しているからだったと思う。詳しくは exec 族 のC言語関数を見ればわかったと思う
時間のかかる処理の結果をループで回すときは、for よりも パイプライン処理をしたほうが無駄が少なくて嬉しい。