シェルスクリプトでは、${1+"$@"} とは何を意味し、"$@" とはどう違いますか?

シェルスクリプトでは、${1+"$@"} とは何を意味し、"$@" とはどう違いますか?

Perlドキュメントではフェレン(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)に文書化された(「代替値を使用」)構文を知っています。しかし、私はそれを信じていません。なぜなら

  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}?この仮説を確認できる人はいますか?

答え1

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

ほとんどの人の祖先です。ボンのような殻ksh、またはbashzsh

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

Bourneシェルの場合(少なくともまだ変更されていないバリエーション):引数がまったくない代わりに、位置引数リストが空の場合"$@"$# == 0)、空の引数に展開します。

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

部分文字列拡張が実行されない場合、bashは以下の文書化された形式を使用して設定されていないかnullの引数をテストします。 コロンを省略すると、設定されていないパラメータのみがテストされます。

${1+"$@"}したがって、Bourneシェルの制限を解決する()設定時にのみ拡張されます。"$@"$1$# > 0

Bourneシェルはこの問題がある唯一のシェルです。最新のs(POSIX仕様にsh準拠しています(Bourneシェルではありません))、この問題はありません。そのため、非常に古いシステムで動作するコードが必要な場合にのみこれを実行できます。標準シェルの代わりに Bourne シェルにすることができます (POSIX は標準がどこにあるかを指定しないため、たとえば Solaris 11 以前の Solaris では、まだ Bourne シェル (特定の問題ではないが)、一般/標準は別の場所 ( ) にあります。shsh/bin/shsh/bin/shsh/usr/xpg4/bin/sh

Perldocページが参照されないのにperlrun問題があります。$0

バラよりhttp://www.in-ulm.de/~mascheck/various/bourne_args/より多くの情報を知りたいです。

答え2

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

command ""

そして

command

場合によっては、渡す引数は空の文字列です。 2番目では、0個の引数が渡されます。

どちらの場合も、「$@」は次のようになります""。ただし、使用は最初の項目に対するもので${1:+"$@"}あり、""2番目の項目にはパラメータは渡されません。これが意図です。

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

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

これは、対話型シェルではなくリモートホスト(返却のみ)で ""実行を試みます。

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

exec は変数を空の文字列ではなく null として正しく解釈するため、対話型シェルがリモートホストで起動されます。

"${parameter:+word}" ("代替値を使用") と同様の変数拡張文字列の使い方については、bash のマニュアルページをご覧ください。

答え3

私はStéphane Chazelasの答えを要約しました。

  • ${1:+"$@"}' $1 が空か設定されていないかをテストします。
  • ${1+"$@"}' は、$1 が設定されていないかどうかをテストします。

したがって、2番目のパラメータ ""を使用すると、$ 1が空であることを意味しますが、空であることをテストせずに設定されたものだけを見て、空であれば$ @を拡張します。 "" で ${1:+"$@"}' を使用すると、拡張されなくなります$@

関連情報