初歩のシェルスクリプトで遊ぶ[ファイルのリネームツール、のようなもの?_(2)]

whileとforのパイプ繋ぎ

  • for.sh
#!/bin/bash

stdin=`cat -`

for LINE in ${stdin} ; do

expr ${LINE} + 1
#echo $(( ${LINE} + 1 ))

done
  • while.sh
#!/bin/bash

while read LINE ; do

expr ${LINE} + 1
#echo $(( ${LINE} + 1 ))

done
$ time seq 0 1300 | ./for.sh 1>/dev/null
real	0m1.022s
user	0m0.868s
sys	0m0.173s

$ time seq 0 1300 | ./while.sh 1>/dev/null
real	0m1.028s
user	0m0.828s
sys	0m0.221s

$ time seq 0 1300 | ./for.sh | ./for.sh | ./for.sh | ./for.sh | ./for.sh 1>/dev/null
real	0m5.203s
user	0m4.089s
sys	0m1.240s

$ time seq 0 1300 | ./while.sh | ./while.sh | ./while.sh | ./while.sh | ./while.sh  1>/dev/null
real	0m2.683s
user	0m3.725s
sys	0m1.395s


whileだと、1行をexprで計算するごとに、1行ずつ出力している。forでは、すべての数字を計算してから、まとめて出力している。
forでは単純に足し算、以上の時間がかかるが、whileでは同時処理をしてくれる。

という、簡単なテストをしてたんだが。


「(1)」に置いてるリネームツールは、forループのほうなわけっすよ。配列に入れたファイル名と拡張子を、コマンドひとつにつき一回ずつ呼び出して、配列に入れなおしている。同時処理はしていない。
もともと、ファイル一つにつきコマンドを一回呼び出す処理、オプション「--once」で、burdockは非常に遅い。これを今のスクリプトのまま改善したいなら、たとえばbashの内部コマンドだけで処理を書いてシェル関数にするとか、いっそbusyboxにするか、とかになるんだけれど。それは限度がある。

なら、まとめてパイプで処理できないかと。「--once」の処理を何度も繰り返すときなら、効果がありそうなんだが。
こんなん考えてるから、いつまでたっても安定せん。



今回は、bashの配列を使ってみよう、evalやIFS変更はなるべく避けよう、多少の遅さよりも読みやすさ優先、で始めたから、あんまりゴチャゴチャにしたくないんすよ。パイプに繋いで複数のコマンドを並列処理させるってなら、どうやって書けばいいだろかなぁ。パイプを繋いだコマンドの文字列を作って、evalで実行するくらいしか、やり方を思いつかん。

現実の道具としては、bash専用の自分用スクリプトなら、高速化のためにevalを乱用するより、読みやすさを重視したほうがいいと思う。

bashに限定せずに他のシェルでも動くようにするのなら、多少の読みにくさ、トラブルの起きやすさは、しょうがない。しょうがないんだけど……readコマンドがbashのでしか使い物にならないから、やっぱりforにするしかない。パイプで繋いでいても、スクリプトの中身がforなら、並列動作になんないんだから、パイプにする必要もないんじゃなかろうか。

書くなら、dashとbusyboxで使えるバージョンのほうかなぁ。