序文:
while
シェルで作業するときは、ループよりもループを実行する方が望ましいこと、およびファイルをコマンド置換でループをfor
使用するべきではないことを常に教えられてきました。私の理解では、これには次のような多くの理由があります。for
cat
for
ループでは、処理するすべてのデータを一度にメモリにロードする必要がありますfor
ループは、デフォルトでは改行ではなく空白で単語分割を行うため、ファイル内のすべてをメモリに保持する必要があることに加えて、メモリを占有する単語分割も多くなりますfor
in
ループは、ステートメント内のすべての読み込みが完了するまで「do の右側」で処理を開始しません。つまり、結果を待っている時間の一部は、「プリロード」している間は実際には何も起きていません。 .
ただし、いくつかの簡単なテストを行ったところ、for
(予想どおり) ループではメモリ消費量が多いように見えますが、ループの実際のパフォーマンスwhile
は低いことがわかりました。それは大きな違いではなく、これが最新のマシンで問題になり始める可能性が高い規模では、おそらく awk または python に切り替えることになるでしょうが、なぜこれが起こっているのかまだ興味があります.
テスト設定:
ファイルの行を /dev/null にエコーするだけの簡単な一連のテストを行いました。私の入力は、それぞれ 100K と 1Mil の IP アドレスを含む 2 つのフラット ファイルです。以下の出力は 1 つのテストですが、これを数回実行すると毎回同様の結果が得られました。2013 MBA (i7、8g Mem) でこのテストを実行していました。
試験結果
Ds-MacBook-Air:~ d$ time for i in $(cat /tmp/ips.100k);do echo $i > /dev/null;done
real 0m1.629s
user 0m1.154s
sys 0m0.480s
Ds-MacBook-Air:~ d$ time for i in $(cat /tmp/ips.mill);do echo $i > /dev/null;done
real 0m17.567s
user 0m12.414s
sys 0m5.131s
Ds-MacBook-Air:~ d$ time while read i;do echo $i > /dev/null;done < /tmp/ips.100k
real 0m2.148s
user 0m1.493s
sys 0m0.655s
Ds-MacBook-Air:~ d$ time while read i;do echo $i > /dev/null;done < /tmp/ips.mill
real 0m21.536s
user 0m14.915s
sys 0m6.617s
Ds-MacBook-Air:~ d$ tail -5 /tmp/ips.100k /tmp/ips.mill
==> /tmp/ips.100k <==
1.1.134.155
1.1.134.156
1.1.134.157
1.1.134.158
1.1.134.159
==> /tmp/ips.mill <==
1.15.66.59
1.15.66.60
1.15.66.61
1.15.66.62
1.15.66.63
Ds-MacBook-Air:~ d$ wc -l /tmp/ips.100k /tmp/ips.mill
100000 /tmp/ips.100k
1000000 /tmp/ips.mill
1100000 total
for
ループとループに関して私が主張したことについて直接の引用はありませんが、while
具体的には ~~TLDP~~ Wooldridge のドキュメント、または別の Bash プログラミング ガイド (簡単なグーグル検索では私がこの数年前にほとんど読んだ正確な場所.)