2016年7月1日金曜日

bashスクリプトの変数のスコープにはまったところと対処方法

The programming pitfalls in variable scope for Bash scripts

bashスクリプトを書いた際、変数が有効なスコープ範囲内にあるはずと思っていたのに値が消えてしまうトラブルにはまってしまいました。
その原因と対処方法をまとめました。


環境

  • Windows 10
  • Cygwin


きっかけは短縮URLの移動先を調べるスクリプト

Twitterのt.coを始め、Google URL Shortenerなど長い文字になりがちなURLを短縮するサービスが広く利用されています。
これらの短縮URLはWebブラウザーなどでクリックすると指定された移動先のURLに移動します。
短縮URLの文字を見ただけでは移動先のサイトは分かりません。
短縮URLの移動先がさらに短縮URLで別の移動先が指定されていることも少なくありません。

そこでCygwinで短縮URLの移動先を再帰的に調べ最後の移動先を表示するbashスクリプトを書いたのですが、変数の値が途中で消えてしまいました。

blog.fujiu.jp bashスクリプトで変数スコープにはまった


curlコマンドをインストールする

curlコマンドが必要です。Cygwin Setupかapt-cygなどでcurlをあらかじめインストールしてください。


失敗したスクリプト

動くはずと思って書いたスクリプトです。


上のスクリプトをファイルに保存しパーミッションを755に設定します。
引数に適当な短縮URLを指定して実行すると、curlコマンドを使って応答ヘッダーを調べます。
移動先が指定されていればそのURLの応答ヘッダーを調べる処理を繰返し、最後の移動先を表示するはずでした。

実際に実行してみると
(1)のstatus変数には間違いなくHTTPステータスが代入されている
(2)のstatus変数は値がカラになっている
という期待を裏切る結果が起きました。


原因

下記サイトを参考にしました。
スマートな紳士のためのシェルスクリプト(8):シェルスクリプト最大の罠、while問題 (1/2)- @IT
http://www.atmarkit.co.jp/ait/articles/1209/14/news147.html
http://www.atmarkit.co.jp/ait/articles/1209/14/news147.html

原因はパイプでつないだ先の変数はパイプ先のみ有効とのことです。
上のスクリプトの場合、パイプでつないだwhile文の内側にある(1)のstatus変数はdoneの直前まで有効ですが、doneより下にある(2)のstatus変数はパイプの外側にあるので別の値を持つ変数だった、ということでした。


解決策

パイプでつないだ先の変数の値を/tmpディレクトリーにファイルとして保存することにしました。


修正したスクリプト

期待通りに動作するように修正したスクリプトがこちらです。


/tmpディレクトリーをRAMディスクに置ければちょっとだけ高速化できそうです。


関連ブログ

[クラウド] BluemixのJavaアプリ開発ではまったところと対処方法
C#のAzure用Webジョブ開発ではまったところ

以上、参考になれば幸いです。

0 件のコメント:

コメントを投稿