徒然日記
2006年9月23日(土) [長年日記]
■ shell scriptのwhile
仕事でshell script書いてたんすよ。だけど、どうにもうまく動かない。
それで挙動を追ってるとwhileの中で変数に代入した値が、ループの外だと空になってる。
さらに、試してみるとwhileの外である変数に代入して、ループの中でも代入を行うと、ループの中では新たに代入された値になるんだけど、外に出ると始めに代入した値に戻ってしまう。
なんでshell scriptなのにscopeをもってるかのように振る舞うんだ?
shell scpriptって全部Global変数でしょ?とか、先輩と一緒に悩んだりしていたのだが、shell scriptの得意な人に聞いたら
「whileの中の変数は外に出せないよ。まるでsopeみたいに。
困るんだよねぇ、ファイルに吐くとかすると効率が悪いし」との事でした
2時間は悩んでた〜〜orz
■ 実例
わかりにくい人のために実例
#!/bin/sh A=1 echo "out of loop 1, A: $A" echo "hoge" | while read line ; do echo "in the loop 2, A: $A" A=2 echo "in the loop 2, A: $A" done echo "out of loop 2, A: $A"
これを実行すると…
$ ./test.sh out of loop 1, A: 1 in the loop 2, A: 1 in the loop 2, A: 2 out of loop 2, A: 1
こうなる
キモイ
キモすぎる〜〜〜〜
■ 今回の敗因
ファイルから1行ずつ読み込んで、該当行があったら抜けて、次の処理に移る。whileはさっさと抜ける、という感じで書いたことだろか…
結局変数を参照するところまで全てwhileでくくって書いたけど、やっぱりキモイなぁ
ちなみに、一緒に悩んでくれた先輩が、自分で今までに書いたscriptを読み返したら、全てwhileの中で参照していた、との事でした
# 無意識にやってたらしい。scope持つって知って驚いてた
# というか、その場にいた他の人も誰も知らなかったw
whileループの done の前に ps 入れて、実行して味噌。<br>からくりの端緒が見つかると思われるので。<br>#変なことを覚えるより、落とし穴に陥らない処理の仕方を考えたほうがよいとおもわれ。
パイプでつないでるからsub shellになってしまうのね…納得<br>whileだけならscopeを持たないようで。(実装依存らしいけれど)
hoge() {<br> local r=""<br> while read foo; do<br> ...<br> done<br> echo $r<br>}<br>みたいなのを用意しといて<br>uga=$(echo "guhehe"|hoge)<br>なんてのをよくやるよ.<br><br>でも,素直にmktempで一時ファイル作った方が楽なときもあるよね.