理系学生日記

おまえはいつまで学生気分なのか

スクリプトに出てくる${1+"$@"}

時々、スクリプトを見ていると ${1+"$@"} なんて記述にでくわす。例えば、これは Perl スクリプトだけれど、cpanm の実装では

|perl|

!/Users/kiririmode/perl5/perlbrew/perls/perl-5.14.1/bin/perl

eval 'exec /Users/kiririmode/perl5/perlbrew/perls/perl-5.14.1/bin/perl -S $0 ${1+"$@"}' if 0; # not running under some shell ||< となっていて、ここには ${1+"$@"} という表現がでてくる。Perl スクリプトに限らず、むしろ目にするのはシェルスクリプトに多い。 検索しても "これが一体何なのか" が分からなくて悶々としていたのだけれど、出てこないのも当然で、単純にシェルによるパラメータ展開の話だった。 具体的には、

|tcsh| ${var+value} ||< は、変数 var が設定されているときにのみ、値 value としてパラメータ展開される。

次に具体例を挙げる。変数 v が未定義の場合は echo しても何も出力されないが、変数 v を定義すると、hello world が出力されるようになる。

|tcsh| $ echo ${v+hello world}

$ v=1 $ echo ${v+hello world} hello world ||<

これを当て嵌めると、${1+"$@"} はすぐに読めるようになる。要するに、第一引数を示す $1 が定義されていれば、全引数 $@ として評価しようという意味合いである。 元より $@ と書いておけば良いじゃないかと思ったけれど、おそらくはこれ、set -u された環境に対する回避策なのだと思う。 シェルによって動作が違うので、ここでは ksh で試すのだけれど、例えば以下のようなシェルスクリプト setu.sh を作成する。単純にシェルスクリプトに与えた引数を出力するだけ。

|tcsh|

!/bin/ksh

echo "Arguments=$@" ||< これを引数なしで実行しても問題にはならず、引数が無いことが正しく表示される。

|tcsh| $ . ./setu.sh Arguments= ||< 一方、set -u した環境で実行してみると、これは $@ が未定義であるとしてエラーとなってしまう。 |tcsh| $ set -u $ . ./setu.sh /bin/ksh: .: line 3: @: parameter not set ||<

一方、setu.sh を次のように書き換えると、

|tcsh|

!/bin/ksh

echo "Arguments="${1+"$@"}"" ||< set -u 環境でもエラーとならない。

|tcsh| $ set -u $ . ~/work/setu.sh Arguments= ||< 世の中には色々なノウハウがあるもんだなと思った。