web-dev-qa-db-ja.com

シェルスクリプトでの$ {1 + "$ @"}の意味と、 "$ @"との違い

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

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

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


編集する

以下の2つの回答は、それが${1:+"$@"}であると想定していることを示しています。 bash(1)に記載されている${parameter:+Word}( "代替値の使用")構文を知っています。しかし、私は納得できません。

  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+"$@"}を使用します。これには one hacker が含まれます。

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

44
200_success

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

これは、kshbashzshのようなほとんどのBourne-like shellsの祖先です。

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

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

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

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

したがって、${1+"$@"}は、"$@"が設定されている場合にのみ$1に展開されます($# > 0)。これは、Bourne Shellの制限を回避します。

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

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

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

54

違いがあります:

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は変数を空の文字列ではなく、何もないものとして正しく解釈するため、リモートホストでインタラクティブシェルを起動します。

"$ {parameter:+ Word}"( "Use Alternate Value")と同様の変数展開文字列の使用法については、bashのマニュアルページをご覧ください。

3
Arcege

StéphaneChazelasの回答をまとめました。

  • $ {1:+ "$ @"} '$ 1がnullまたは未設定かどうかをテスト
  • $ {1 + "$ @"} '$ 1が設定されていない場合のテスト

したがって、パラメーター「」で2番目のパラメーターを使用すると、$ 1がnullであることを意味しますが、nullであるかどうかはテストされません。すでに設定されているにもかかわらず、空であるかどうかが確認されるため、$ @が展開されます。 、ただし$ {1:+ "$ @"} 'と ""を一緒に使用すると、展開されません$@もう。

0
Kevin