二十五日半狂乱4日目(の分)の記事
前回引用したkilltreeスクリプトの中に以下のようなコードがあった.
local _sig=${2:-TERM}
この${2:-TERM}は、変数展開されたタイミングで、$2に値が設定されていない場合にTERMを出力する.
すなわち、結果的に$2が空だった場合は変数_sigにTERMが代入される.
なのでkilltreeは第二引数でシグナルを指定せずに実行したらデフォルトでkill -TERM [pid]が実行される.
$ bash killtree.bash 4003 kill -TERM 4004 kill -TERM 4005 kill -TERM 4006 kill -TERM 4007 kill -TERM 4008 kill -TERM 4003 [2]+ Stopped bash mkpstree.bash
手元にあるUNIXシェルスクリプトコマンドブックを見てみると、同書ではこの機能を「拡張的な変数展開」と呼んでいて、他にも便利な機能が色々解説されていた.
- 作者: 山下哲典
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2010/01/28
- メディア: 単行本
- 購入: 2人 クリック: 46回
- この商品を含むブログ (2件) を見る
買った技術書の後半を読み切らずに本棚へしまっていたことが白日の下に晒されつつ、便利な変数展開をメモ.
シェル変数のデフォルト値を設定する
冒頭の変数展開は、変数に値が設定されていなければ、代わりに指定した値を返す.
$ echo ${var:-hoge} hoge $ var=foo $ echo ${var:-hoge} foo $ var= $ echo ${var:-hoge} hoge $ echo $var #varにhogeが代入されるわけではない
foo=${var:-hoge}
のようにvarとは別のシェル変数にデフォルト値を設定したい場合ならこれで事足りるが、var自身にデフォルト値を設定したい場合は${var:=word}
が使える.
3行目はkilltreeと同じ用途のサンプル.それはさておき.
目的は変数varへのデフォルト値設定なので、変数展開だけを行えば目的は達成できるが、7行目のような感じで書いても所詮変数なので上手くいかない. 11行目のように変数展開を行った上で出力を捨てる方法もあるが、スマートじゃない. これに対して同書では15行目や20行目のコマンド:で変数展開だけを行うテクニックが紹介されていた.
コマンド:は何もせずに終了コード0を返すだけコマンドだが、引数を取る場合は、引数が拡張的な変数展開の場合にそれをチェックして変数展開を行ってくれる.
これでももう: ${var:=default_value}
とするだけで、
if [ "$var" = "" ]; then var=default_value fi
などと煩わしいこと*1をしなくて済む.
無知って怖い.
未初期化時にメッセージを出力してスクリプトを終了する
ずっとシェルスクリプトで変数未初期化の検知は、やりにくい上に面倒だ、デバッグも泥臭くてしんどい、などと思っていたがスマートな方法があった.
varに値がセットされていない場合、以下のような感じでエラーメッセージを出力できる*2.
$ : ${var:?"error message"} bash: var: error message
このコードがスクリプト上にあった場合には、その時点でシェルを終了して上記のようなエラーを出力してくれる.
変数未定義が致命的なエラーとなるスクリプトの場合には、検知した時点でスクリプトの処理を中断して適切なエラーメッセージを吐き出すことができる.
また、このメッセージ出力は標準出力でも標準エラー出力でもなく、メッセージをリダイレクトすることも、変数に代入することもできないので、常に強制的に処理を中断させることができる.
$ echo ${var:?"error message"} > /dev/null 2>&1 bash: var: error message
同書には、他にも:を省略した場合の挙動や、bashで追加された拡張的な変数展開なども紹介されている.