it-swarm.com.de

Was bedeutet $ {1 + "$ @"} in einem Shell-Skript und wie unterscheidet es sich von "$ @"?

In der Perl-Dokumentation schlägt perlrun (1) vor, Perl-Skripte mit einem zweisprachigen Shell/Perl-Header zu starten:

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

Was bedeutet ${1+"[email protected]"}? Ich habe stattdessen versucht, "[email protected]" Zu verwenden (mit Bash als/bin/sh), und es scheint genauso gut zu funktionieren.


Bearbeiten

Zwei Antworten unten sagen, dass es ${1:+"[email protected]"} Sein soll. Mir ist die in bash (1) dokumentierte Syntax ${parameter:+Word} ("Use Alternate Value") bekannt. Ich bin jedoch nicht überzeugt, weil

  1. Sowohl ${1+"[email protected]"} Als auch "[email protected]" Funktionieren einwandfrei, auch wenn keine Parameter vorhanden sind. Wenn ich simple.sh als erstelle

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

    und question.sh as

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

    Ich kann beide dazu bringen, identisch zu arbeiten:

    $ ./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. Andere Quellen im Internet verwenden ebenfalls ${1+"[email protected]"}, Einschließlich ein Hacker , der zu wissen scheint, was er tut.

Vielleicht ist ${parameter+Word} Eine undokumentierte alternative (oder veraltete) Syntax für ${parameter:+Word}? Könnte jemand diese Hypothese bestätigen?

44
200_success

Das dient der Kompatibilität mit der Bourne Shell. Die Bourne Shell war eine alte Shell, die 1979 erstmals mit Unix Version 7 veröffentlicht wurde und bis Mitte der 90er Jahre als /bin/sh auf den meisten kommerziellen Einheiten.

Es ist der Vorfahr der meisten Bourne-ähnlichen Muscheln wie ksh, bash oder zsh.

Es hatte ein paar unangenehme Merkmale, von denen viele in ksh und den anderen Shells und der neuen Standardspezifikation von sh behoben wurden. Eines davon ist das Folgende:

Mit der Bourne Shell (zumindest die Varianten, bei denen dies nicht behoben wurde): "[email protected]" wird zu einem leeren Argument erweitert, wenn die Liste der Positionsparameter leer ist ($# == 0) statt überhaupt kein Argument.

${var+something} erweitert sich zu "etwas", es sei denn $var ist nicht gesetzt. Es ist in allen Shells klar dokumentiert, aber in der bash -Dokumentation schwer zu finden, da Sie diesen Satz beachten müssen:

Wenn Sie keine Teilzeichenfolgenerweiterung durchführen, testen Sie mithilfe der unten dokumentierten Formulare einen Parameter, der nicht festgelegt oder null ist. Das Weglassen des Doppelpunkts führt zu einem Test nur für einen Parameter, der nicht gesetzt ist .

Damit ${1+"[email protected]"} erweitert sich zu "[email protected]" nur wenn $1 ist gesetzt ($# > 0), die diese Einschränkung der Bourne-Shell umgeht.

Beachten Sie, dass die Bourne-Shell die einzige Shell mit diesem Problem ist. Moderne shs (dh sh, die der POSIX-Spezifikation von sh entsprechen (was die Bourne-Shell nicht ist)) haben dieses Problem nicht. Sie brauchen das also nur, wenn Sie Ihren Code benötigen, um auf sehr alten Systemen zu arbeiten, auf denen /bin/sh kann eine Bourne-Shell anstelle einer Standard-Shell sein (beachten Sie, dass POSIX den Speicherort des Standards sh nicht angibt, z. B. unter Solaris vor Solaris 11, /bin/sh war immer noch eine Bourne Shell (obwohl es dieses spezielle Problem nicht gab), während sich das normale/standard sh an einem anderen Ort befand (/usr/xpg4/bin/sh)).

Es gibt ein Problem in dieser perlrun Perldoc-Seite in dieser $0 wird jedoch nicht zitiert.

Weitere Informationen finden Sie unter http://www.in-ulm.de/~mascheck/various/bourne_args/ .

54

Es gibt einen Unterschied zwischen:

command ""

und

command

In einem übergeben Sie ein Argument, das eine leere Zeichenfolge ist. Im zweiten Fall werden keine Argumente übergeben.

Für beide entspricht "$ @" der gleichen Sache: "". Aber mit ${1:+"[email protected]"} wäre "" für das erste und keine Argumente für das zweite übergeben, was die Absicht war.

Dies ist wichtig, wenn Sie das folgende Skript namens sshwrapper ausführen, das Sie mit einem optionalen Befehl oder ohne Argumente aufrufen, um eine interaktive Shell zu erhalten.

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

Dies würde versuchen, "" auf dem Remote-Host auszuführen (der gerade zurückkehrt), es wäre keine interaktive Shell.

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

Startet eine interaktive Shell auf dem Remote-Host, da der Exec die Variable korrekt als nichts und nicht als leere Zeichenfolge interpretiert.

Informieren Sie sich in den Bash-Handbuchseiten über die Verwendung von "$ {parameter: + Word}" ("Use Alternate Value") und ähnlichen variablen Erweiterungszeichenfolgen.

3
Arcege

Ich habe die Antwort von Stéphane Chazelas zusammengefasst:

  • $ {1: + "$ @"} 'testet, ob $ 1 null oder nicht gesetzt ist
  • $ {1 + "$ @"} 'testet, ob $ 1 nicht gesetzt ist

wenn Sie also den zweiten mit dem Parameter "" verwenden, bedeutet dies, dass $ 1 null ist, aber nicht getestet wird, ob er null ist oder nicht. Es wird nur angezeigt, dass er bereits festgelegt wurde. Es ist jedoch leer oder nicht, sodass $ @ erweitert wird , aber wenn Sie $ {1: + "$ @"} 'mit "" verwenden, wird [email protected] nicht mehr erweitert.

0
Kevin