シェルスクリプトでの$ {1 +“ $ @”}の意味と、「$ @」との違いは何ですか?


43

Perlのドキュメントでは、perlrun(1)は、バイリンガルシェル/ Perlヘッダーを使用してPerlスクリプトを起動することを提案しています。

#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS $0 ${1+"$@"}'
    if 0;

どういう${1+"$@"}意味ですか?"$@"代わりに(Bashを/ bin / shとして使用して)使用してみましたが、同様に機能するようです。


編集

以下の2つの回答は、にあるはずだと言っています${1:+"$@"}${parameter:+word}bash(1)で文書化されている( "Use Alternate Value")構文を知っています。しかし、私は納得できません。なぜなら

  1. 両方${1+"$@"}"$@"うまく、パラメータがない場合でも作業。としてsimple.shを作成した場合

    #!/bin/sh
    eval 'exec /usr/bin/perl -x -S -- $0 "$@"'
        if 0;
    #!perl
    use Data::Dumper;
    print Dumper(\@ARGV);

    およびquestion.shとして

    #!/bin/sh
    eval 'exec /usr/bin/perl -x -S -- $0 ${1+"$@"}'
        if 0;
    #!perl
    use Data::Dumper;
    print Dumper(\@ARGV);

    私は両方を同じように動作させることができます:

    $ ./question.sh 
    $VAR1 = [];
    $ ./question.sh a
    $VAR1 = [
              'a'
            ];
    $ ./question.sh a 'b c'
    $VAR1 = [
              'a',
              'b c'
            ];
    $ ./question.sh ""
    $VAR1 = [
              ''
            ];
    $ ./simple.sh 
    $VAR1 = [];
    $ ./simple.sh a
    $VAR1 = [
              'a'
            ];
    $ ./simple.sh a 'b c'
    $VAR1 = [
              'a',
              'b c'
            ];
    $ ./simple.sh ""
    $VAR1 = [
              ''
            ];
  2. インターネット上の他のソースもを使用して${1+"$@"}おり、その中にはハッカーが何をしているのかを知っているように見えるハッカーもいます。

おそらく${parameter+word}、文書化されていない代替の(または非推奨の)構文${parameter:+word}ですか?誰かがその仮説を確認できますか?


回答:


53

これは、Bourneシェルとの互換性のためです。Bourneシェルは、1979年にUnixバージョン7で最初にリリースされた古いシェルで/bin/sh、ほとんどの商用Unicesのように90年代半ばまでまだ一般的でした。

それはほとんどのの祖先であるボーンのようなシェルのようなkshbashまたはzsh

いくつかの厄介な機能があり、その多くは修正されkshています。他のシェルとの新しい標準仕様はsh、その1つです。

Bourneシェル(少なくとも修正されていないバリアント):"$@"位置パラメータのリストが空の場合($# == 0引数なし)ではなく1つの空の引数に展開されます。

${var+something}$var設定されていない限り、「何か」に展開されます。すべてのシェルで明確に文書bash化されていますが、この文に注意を払う必要があるため、文書で見つけるのは困難です:

以下に説明するフォームを使用して部分文字列展開を実行しない場合、bashは未設定またはnullのパラメーターをテストします。 コロンを省略すると、設定されていないパラメーターのテストのみが行われます

だから${1+"$@"}に展開"$@"する場合にのみ$1設定されている($# > 0)の周りに働くことBourneシェルの制限。

Bourneシェルがその問題を抱えている唯一のシェルであることに注意してください。Modern shs(BourneシェルではないshPOSIX仕様に準拠しているsh)には、この問題はありません。したがって/bin/sh、標準シェルではなくBourneシェルである可能性がある非常に古いシステムでコードを動作させる必要がある場合にのみ必要です(POSIXは標準の場所を指定しないshため、たとえばSolaris 11より前のSolarisでは/bin/sh通常の/標準shが別の場所にあったのに(まだその特定の問題はありませんでしたが)Bourneシェルでした(/usr/xpg4/bin/sh))。

ただし、引用されていないperlrunperldocページに問題があり$0ます。

詳細については、http://www.in-ulm.de/~mascheck/various/bourne_args/を参照してください


家宝では再現できません。おそらくSolarisには適用されません。
-ormaaj

2
@ormaaj。はい、リンクしたページをご覧ください。SVR3で修正され、5以上のSolaris / SunOSはSVR4にリベースされました。そのページには、4.1.xにも問題はなかったと書かれています。
ステファンシャゼル

ああ、分かった。<3 Mascheckページ。
-ormaaj

3

次の間に違いがあります。

command ""

そして

command

1つでは、空の文字列である1つの引数を渡します。2番目では、渡される引数はありません。

どちらの場合も、「$ @」は同じものに相当します""。しかし、使用${1:+"$@"}するの""は最初の引数であり、2番目の引数は渡されません。これが目的です。

これは、sshwrapperと呼ばれる以下のスクリプトを実行している場合に重要になります。sshwrapperは、オプションのコマンドまたは引数なしで呼び出して、対話型シェルを取得します。

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" "$@"

これは、リモートホスト(「戻る」だけ)で「」を実行しようとしますが、インタラクティブシェルではありません。

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" ${1:+"$@"}

execは変数を空の文字列ではなく、何も正しく解釈しないため、リモートホストでインタラクティブシェルを起動します。

bashのマニュアルページの「$ {parameter:+ word}」(「代替値を使用」)および同様の変数展開文字列の使用法を参照してください。


これはBourneシェルにのみ適用されているようだではない任意のPOSIX準拠のためにsh(他の回答を参照してください)実装。
törzsmókus

4
いいえ、空の${1:+"$@"}場合$1は引数なしに展開されます。あなたが欲しい${1+"$@"}。基本的には逆になります。
ステファンシャゼル

0

ステファン・シャゼラスの答えを要約しました:

  • $ {1:+ "$ @"} '$ 1がヌルまたは未設定かどうかをテスト
  • $ {1 + "$ @"} '$ 1が未設定かどうかをテスト

したがって、パラメータ ""で2番目のパラメータを使用すると、$ 1はnullになりますが、nullかどうかはテストされず、空かどうかにかかわらず既に設定されていることがわかります。 、しかし「」で$ {1:+ "$ @"} 'を使用すると、それ$@以上展開されません。


7
これは確かに要約されていますが、明確ではないかもしれません
...-Archemar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.