きたへふ(Cチーム)のブログ

ファミスタとは特に関係ありません。タブレット・スマホをご利用の方は、できればPCモードで御覧ください。

Solarisの/bin/shの変数の挙動について(サブシェルの問題)

2005年12月15日 | サーバ・プログラム
私はお仕事でSolarisサーバの管理をするときにBourneシェルのスクリプトを
よく作成するのですが、while (do~done)のブロック中に操作した変数の値が
変更されていない事象が発生して、頭を抱えていました。
その件についての議論をコピペします。

UNIX板 シェルスクリプト総合 その4 より
http://pc8.2ch.net/test/read.cgi/unix/1131026501/


【2011.6.18 追記】
 gooブログの仕様で、半角の<で始まる英数字が連続すると(エスケープ
させても)文字化けする個所があるので、一部全角文字に置き換えています。




554 名無しさん@お腹いっぱい。 sage 2005/12/10(土) 17:46:47
Solaris8の/bin/shの変数の挙動について教えてください。

COUNTという変数があって

----
COUNT=0 ・・・0で初期化
while ほげ
do
   :
  (whileループ中にカウントアップ処理)
  echo "COUNT=$COUNT" ・・・・(1)
   :
done
echo "ループ終了後のCOUNT=$COUNT" ・・・・(2)
----

という処理を実行させたところ、whileループ中の(1)の処理では
正常にカウントアップされた値が表示されるのですが、
ループ終了直後の(2)の値は、何度実行させても0になります。(;´Д`)

こうなる原因はなんでしょうか?また改善方法についてヒントをください。
おながいします。



555 名無しさん@お腹いっぱい。 sage 2005/12/10(土) 18:01:22
>>554
サブシェルで実行されてるから



556 名無しさん@お腹いっぱい。 sage 2005/12/10(土) 18:08:24
サブシェルの問題だと思うが、そのコードだと説明不十分
たとえば下のコードならちゃんと 10 と出る。(Sol8)

#!/bin/sh
count=0
while [ $count -lt 10 ]
do
 count=`expr $count + 1`
 echo "count=$count"
done
echo "last:$count"

サブシェルの問題はUNIX FAQに載ってる
http://www.nurs.or.jp/~asada/FAQ/UNIX/section3.8.html



557 554 sage 2005/12/10(土) 23:17:02
>>555-556
ありがとうございますた。

とりあえず下記のサンプルで試してみました

パターン1
----------------
#!/bin/sh
COUNT=0
while read i
do
    COUNT=`expr $COUNT + 1`
    echo "now count = $COUNT"
done </etc/passwd
echo "Last count = $COUNT"
----------------


パターン2
----------------
#!/bin/sh
COUNT=0
cat /etc/passwd | while read i
do
    COUNT=`expr $COUNT + 1`
    echo "now count = $COUNT"
done
echo "Last count = $COUNT"
----------------



558 554 sage 2005/12/10(土) 23:17:33
パターン3
----------------
#!/bin/sh
COUNT=0
exec 9<&0 < /etc/passwd
while read i
do
    COUNT=`expr $COUNT + 1`
    echo "now count = $COUNT"
done
exec 0<&9 9<&-
echo "Last count = $COUNT"
----------------

そうしたら、パターン1とパターン2のLast countは0のままで、
パターン3は正確な値がでました。
ちなみにパターン1のシェル指定を/bin/bashに変えたらあっさりと
正確な値が出たので、とりあえずはbashで逃げることにします。(;´Д`)



559 名無しさん@お腹いっぱい。 sage 2005/12/10(土) 23:33:09
>>558
bashismですね。



560 名無しさん@お腹いっぱい。 sage 2005/12/11(日) 01:13:02
bourne シェルの有名な欠点だな。

kshにすれば、パターン1もパターン2も値を引き継げる。

ちなみに、bashは変態仕様なんで、
パターン1は値を引き継げるけど、パターン2はダメ。



563 名無しさん@お腹いっぱい。 sage 2005/12/11(日) 03:40:29
>>560
bash はパイプライン中に変数を定義しても
ダメみたいだな。

$ bash
$ a=1
$ echo $a
1
$ ls | a=2
$ echo $a
1



561 sage 2005/12/11(日) 01:56:05
うん、Solaris決め打ちでいいならkshにすべきだよね。



562 名無しさん@お腹いっぱい。 sage 2005/12/11(日) 03:10:01
zsh も、ksh と同様パターン1~パターン3全て動くんだよね。

ksh だと対話的に使った場合の機能がちょっと足らんという場合、
bash を使う人が多いんだけど、zsh の方が幸せだと思う。

スクリプトで使う場合には、ksh の方が小さいからいいだろうね。



564 名無しさん@お腹いっぱい。 sage 2005/12/11(日) 10:11:03
kshって昔からSolaris(というかSVR4)に入っているのに
あんまり使われてないね。
メニュー表示(select)とかシェルスクリプトに向いてる機能があるのに



565 554 sage 2005/12/11(日) 10:43:33
コメントありがとうございます。
bashにもそういうクセがあるとは知らなかったし、Solaris標準のシェルであれば
何でもいいので、kshかzshを使ってみようと思います。



566 名無しさん@お腹いっぱい。 sage 2005/12/11(日) 10:59:04
zsh は Solaris 標準じゃねーぞ。
今は勝手に入ってることが多いのはたしかだけど、
インストールのしかたによっては zsh は入らないこともあったはず。



上記の話を総合すると、下記のようなプログラム構成の場合

--------------------
1行目 変数a=0 で初期化
2行目 while (条件式)
3行目 do
4行目  変数a=10と変更
5行目 done
6行目 変数aの値を表示
--------------------

通常のプログラムでは、1行目で宣言した変数aのスコープは全体に渡るので、
6行目を実行させると(1回はwhileループを通るとして) a=10と表示されるのが
本来想定される動きである。

ところが Bourneシェルでは、whileのような制御構造をリダイレクトすると
(引用文のサンプル1のように、whileに対して </etc/passwd のように
ファイルをリダイレクトで読み込ませると)、その部分がサブシェル(≒関数)
として動くため、上記でいう4行目の変数aは、1行目や6行目の変数aとは
別物として扱われる動きになるらしい。
だから6行目の変数aの値が0として表示されるとのこと。

ちなみにbashは上記のようなファイルリダイレクトだと正確な値が出るものの、
引用文のサンプル2のように、whileに対して cat /etc/passwd | とパイプライン
経由でファイルの中身を渡してあげるパターンでは、NGになるようである。
(これがbashの変態仕様らしい)

ともかく、お勉強になりました。




UNIXシェルスクリプトコマンドブック 第2版
山下 哲典
ソフトバンククリエイティブ

このアイテムの詳細を見る

UNIXシェルスクリプトハンドブック (Technical handbook series (001))
関根 達夫
ソフトバンククリエイティブ

このアイテムの詳細を見る

コメント   トラックバック (1)

小倉~博多間の新幹線に思う

2005年12月14日 | 旅行・鉄道
11月下旬のことですが、2chに渡辺淳一氏のブログが紹介されていました。
紹介というよりかは、晒されていたというべきか…。

渡辺淳一 堅すぎる車掌さん
http://watanabe-junichi.net/archives/2005/11/post_8.html

【2010.4.17 一部追記】
 現在は上記ページは削除されているみたいです。ただしWebArchiveに
履歴が残っている
ので、原文を追いたい方はこちらを参照されてください。


内容は見ての通りですが、要約すると「自由席の切符で指定席に乗っていたら
車掌から自由席に移動するように求められた。そして隣のグリーン車に移ったら、
また車掌から移動を求められた。そして渡辺氏は『君きみ、これくらいは大目に
見るものだよ、本当に融通がきかないね』と説教した。」というものです。

逆ギレもいいとこな非常識な言動だなぁ…と思いつつ、どんな辛辣なコメントが
寄せられているのか(笑)、わくわくして下欄のコメント欄を見たところ、残念ながら
ここのブログはコメントを受け付けないようになっていました。

その代わりトラックバックは有効になっていたので、リンク先を見てみたところ、
案の定、非難囂々の状態になっていました。なんせトラックバックの先頭に2chの
「DQNな乗客をみたら報告するスレ」があったぐらいですから。(笑)

その中で目を引いたのが渡辺淳一オフィシャルBlog 私設コメント欄でした。
本家にコメント欄が無い分、こちらにコメントが続々と寄せられていました。
(こちらにトラックバックさせていただきました)

こんな騒ぎもあってか、久しぶりに渡辺淳一氏のブログを見たところ、
トラックバックも一斉に削除されてしまっていました。
上記ブログもトップページからリンクを辿れなくなっています。

とりあえずインフォメーションに経緯の説明があるものの、コメントもトラックバックも
自由に受け付けないという姿勢は、正直なところ文化人としてかなりみっともない、
(車掌に毒づいた言動以上に恥ずかしい)と感じます。
コメントもトラックバックも受け付けないなら、ホームページとして書いてれば?
って言いたくなりますね。

【2014/05/05 追記】
 渡辺淳一氏が4月30日にお亡くなりになられたことが本日報じられました。ご冥福をお祈りいたします。



それで、タイトルに戻って小倉~博多間の新幹線についてですが、ちょうど
祖父の戦争体験談を聞いてみたの件で大分に帰省したとき、同じ区間の
新幹線に乗りました。(大分→小倉→博多→福岡空港→羽田空港という経路)

以前、のぞみ号が全車指定席の頃は、小倉→博多間は空いている指定席に座っても
良いという運用でした。(小倉駅のホームでもそのようにアナウンスしていた)。

ところがこの前乗ったときは「指定券を持っていない香具師は自由席に逝け」との
アナウンスがされていました。恐らくのぞみ号に自由席ができてからは、元通りの
運用に戻ったのではないかと思われます。

結局私は重たい荷物をヘコヘコ持って、自由席のあるホームの端っこに移動して
乗車しました。幸いにして自由席に座ることができたのですが、平日昼間だったにも
かかわらず、自由席は満席状態でした。

渡辺氏ではないですが、小倉→博多間に限っては、空いている指定席は
(以前のように)自由に座らせてもらえないかなぁ…と少しは思った次第でした。



【2010.8.8 追記】
 現在、小倉→博多間の新幹線の自由席は、のぞみ号は規定通り端っこの
自由席車両にのみ乗車可能ですが、ひかり号(レールスター)は指定席車両でも
席が空いていれば着席してもよいみたいです(当然グリーン車は除く)。
ただし私のうろ覚えの可能性があるので、詳細は小倉駅の駅員さんに聞くか、
構内アナウンスを確認してください。


【2011.2.9 追記】
 小倉→博多間の新幹線の座席ですが、2011/3/12のダイヤ改正からは、
 (九州新幹線が全線開通して博多駅が終点でなくなることに伴い)、
 ひかり号・こだま号の指定席は空いていても自由席券では使用できない
 ことになりましたのでご注意ください。


【2014.1.5 追記 (Unknownさん向け返信)】
 詳しい事情をご存じなさそうなので、最初のコメントの方向けに、
 ちょっと補足しておきます。

 このブログを書いた当時、小倉~博多間は新幹線で15分の隣の駅で、
 博多駅は終点でした。都内の感覚でいうと、新横浜や大宮から
 東京(品川や上野)に行くようなものです。関西の感覚でいうと、
 新大阪止まりの新幹線に京都から乗るようなものでしょうか。

 ただし小倉~博多間は約70kmもあり、在来線特急で45分、
 快速列車で70分程度もかかるため、小倉~博多間を新幹線で
 移動する乗客も多くいます。

 そして小倉~博多間の新幹線特急券は、自由席で940円なのに対し、
 繁忙期ののぞみ号の指定席だと2590円もするので、たかだか15分
 1区間のためだけに、この差額を払う人などいないのが実情です。

 また東京・大阪方面からやってくる新幹線は、小倉駅でごっそり
 乗客が下車して、博多までは席が空いていることが多いので、
 最終運転区間となる小倉⇒博多間は、長い間JRの厚意で空いている
 指定席に座らせてもらえていたのですが、九州新幹線開通後は、
 そうした運用は全く行われなくなったという話です。

 小倉~博多間で新幹線を使う地元民からすると、これまであった
 便利な制度がなくなったので残念だなぁ…とグチっているだけなので、
 元に戻せと声高に叫んでいる訳ではないですよ。
コメント (2)