55332


ブルース・ブリン書「入門UNIXシェルプログラミング」の「2.5 位置パラメタ」にて以下のような記述がありました。

> 一般的には、前節で説明した `${variable+value}` の形式を使うのが最適でしょう。
[code]

>     ${@+"$@"}
>  
[/code]

>
> こう書くことで、位置パラメタに何もセットされていない場合には何もしない、という条件を作れます。  
>  参考までに記しておきますが、以下のように記述すると、あるシェルスクリプトに渡した引数を、まったくそのままの形で別の command
> というコマンドに渡す書き方になります。
[code]

>     command ${@+"$@"}
>  
[/code]

>
> あるいは、次のように書いてもいいでしょう。
[code]

>     if [ $# -eq 0]; then
>         command
>     else
>         command "$@"
>     fi
>  
[/code]

`$@` は引数全体を表す特殊変数であり、`${@+"$@"}` はスクリプトに引数が渡されていない場合は `$@` として、引数が渡されている場合は
`"$@"` として動作する書き方です。

これを確認するために、以下のような引数をそのまま出力するシェルスクリプトを用意しました。

[code]

    [~]$ cat atvars.sh
    #!/bin/sh
    echo "length=$#"
    ruby -e "p ARGV" $@
    ruby -e "p ARGV" "$@"
    ruby -e "p ARGV" ${@+"$@"}
    
[/code]

このスクリプトに引数を渡して、どのように動作するのか確認してみます。  
（macOS および Debian9.9 の `/bin/{sh,bash}` にて確認。すべて同じ出力でした）

[code]

    ~$ chmod u+x ./atvars.sh
    ~$ ./arvars.sh 123 "hello world"
    length=2
    ["123", "hello", "world"]
    ["123", "hello world"]
    ["123", "hello world"]
    ~$ ./atvars.sh ""
    length=1
    []
    [""]
    [""]
    ~$ ./atvars.sh 
    length=0
    []
    []
    []
    
[/code]

この結果だけを見ると `"$@"` と `${@+"$@"}` は同じ動作をしているように思えました。

それならば常に `"$@"` を使う方が（書き方も短いし）良さげに思えるのですが、`${@+"$@"}`
が役に立つのはどういった場面が考えられるのでしょうか？ それとも sh/bash や sh
のバージョンの違いによって挙動が異なることを考慮しての記法なのでしょうか？


CC BY-SA 4.0
2019-05-28T19:14:19.653
55320
2021-07-31T11:18:33.077
2019-05-29T16:02:10.250
3068
2391
question
shellscript
変数 ${@+"$@"} はどのような場面で役立つのか


> `${@+"$@"}` はスクリプトに引数が渡されていない場合は `$@` として、引数が渡されている場合は `"$@"` として動作する書き方です

いいえ。「`${foo+"$bar"}` は `$foo` が未定義なら何もせず、定義されていれば "$bar" を展開」ということです。これが `$@`
の場合は解釈がシェルの実装によって揺れがあります。

  * POSIX sh (推測), AT&T ksh, mksh, pdksh, bash 
    * `${@+"$bar"}` は `$@` が空配列なら何もせず、空配列でなければ "$bar" を展開
  * dash, zsh 
    * `${@+"$bar"}` は (`$@` は常に未定義ではないので?) "$bar" を展開

よって、`${@+"$@"}` ではなく、シェル実装によって動作の変わらない `${1+"$@"}`
を使うことを推奨します。個人的な経験でも`${1+"$@"}` のほうばかり目にします。(`${@+"$@"}` は今回初見)

さて、ようやく本題の `${1+"$@"}` という書き方の存在意義ですが、ほとんどのシェル実装では `"$@"`
と差はありません。よってほとんどの場合はどちらもで構いません。ただし bash 4.0.0 では `set -u` 時 (未定義の変数参照時に
`unbound variable` エラーとして終了する) に位置パラメーター (`$@` のことです) を参照すると `$@: unbound
variable` エラーになっていまうバグがあります。

  * <https://twitter.com/grethlen/status/1122505556105867264>

こういった例もあるので `"$@"` より `${1+"$@"}` という書き方のほうが安全です。

  * <https://dev.to/greymd/why-1-is-used-in-shell-script-364h>

個人的には `"$@"` で構わないと思います。

> 「コロン（：）は省略可能です。」

省略可能なのではありません。`:` の有無で動作が異なります。`:` なしの場合は「変数が未定義かどうか」で判定され、`:`
ありの場合は「変数が未定義あるいは値が空文字列かどうか」で判定されます。(`$@` の場合は上記の通り空配列かどうかで判定するシェル実装がある)


CC BY-SA 4.0
2019-05-29T04:33:33.830
55332
2019-05-30T07:00:20.977
2019-05-30T07:00:20.977
3061
3061
55320
answer


2021年7月に `${@+“$@”}` は未定義（unspecified）であると POSIX の仕様で明確にすることが決定しました。次の改定（Issue
8？)には反映されると思います。よって役に立つ場合はあるかもしれませんが、シェルによって動作が異なるので使用しないほうが良いでしょう。

<https://austingroupbugs.net/view.php?id=1478>

> If parameter is '*' or '@', the result of the expansion is unspecified.


CC BY-SA 4.0
2021-07-31T11:18:33.077
80506
2021-07-31T11:18:33.077
47538
55320
answer