理系学生日記

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

忍者TOOLS

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

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

#!/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 スクリプトに限らず、むしろ目にするのはシェルスクリプトに多い。
検索しても "これが一体何なのか" が分からなくて悶々としていたのだけれど、出てこないのも当然で、単純にシェルによるパラメータ展開の話だった。
具体的には、

${var+value}

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

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

$ echo ${v+hello world}

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

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

#!/bin/ksh

echo "Arguments=$@"

これを引数なしで実行しても問題にはならず、引数が無いことが正しく表示される。

$ . ./setu.sh
Arguments=

一方、set -u した環境で実行してみると、これは $@ が未定義であるとしてエラーとなってしまう。

$ set -u
$ . ./setu.sh
/bin/ksh: .: line 3: @: parameter not set

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

#!/bin/ksh

echo "Arguments="${1+"$@"}""

set -u 環境でもエラーとならない。

$ set -u
$ . ~/work/setu.sh 
Arguments=

世の中には色々なノウハウがあるもんだなと思った。