Co oznacza $ {1 + „$ @”} w skrypcie powłoki i czym różni się od „$ @”?

43

W dokumentacji Perla perlrun (1) sugeruje uruchamianie skryptów Perla przy użyciu dwujęzycznej powłoki / nagłówka Perla:

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

Co ${1+"$@"}znaczy Próbowałem użyć "$@"zamiast tego (używając Bash jako / bin / sh) i wydaje się, że działa równie dobrze.


Edytować

Dwie odpowiedzi poniżej mówią, że tak powinno być ${1:+"$@"}. Mam świadomość ${parameter:+word}składni („Użyj wartości alternatywnej”) udokumentowanej w bash (1). Nie jestem jednak przekonany, ponieważ

  1. Zarówno ${1+"$@"}i "$@"działać dobrze, nawet gdy nie ma żadnych parametrów. Jeśli utworzę simple.sh jako

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

    i question.sh as

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

    Mogę sprawić, by obie pracowały identycznie:

    $ ./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. Korzystają również inne źródła w Internecie ${1+"$@"}, w tym jeden haker, który zdaje się wiedzieć, co robi.

Być może ${parameter+word}jest to nieudokumentowana alternatywna (lub przestarzała) składnia ${parameter:+word}? Czy ktoś mógłby potwierdzić tę hipotezę?

200_sukces
źródło
Wygląda jak grawlixes
Martin Thoma

Odpowiedzi:

53

To dla kompatybilności z powłoką Bourne'a. Powłoka Bourne'a była starą powłoką, która została po raz pierwszy wydana z Unixem w wersji 7 w 1979 roku i nadal była popularna do połowy lat 90., jak /bin/shw większości komercyjnych Unics.

Jest przodkiem najbardziej Bourne podobnych powłok , takich jak ksh, bashlub zsh.

Miał kilka niezręcznych funkcji, z których wiele zostało naprawionych, ksha inne powłoki i nową standardową specyfikację sh, z których jedna to:

Z powłoką Bourne'a (przynajmniej te warianty, w których nie został naprawiony): "$@"rozwija się do jednego pustego argumentu, jeśli lista parametrów pozycyjnych jest pusta ( $# == 0) zamiast żadnego argumentu.

${var+something}rozwija się do „czegoś”, chyba że $varjest rozbrojone. Jest to wyraźnie udokumentowane we wszystkich powłokach, ale trudno je znaleźć w bashdokumentacji, ponieważ należy zwrócić uwagę na to zdanie:

Gdy nie wykonuje się rozszerzenia podciągów, korzystając z formularzy udokumentowanych poniżej, test bash dla parametru, który jest nieustawiony lub zerowy. Pominięcie dwukropka powoduje tylko test parametru, który nie jest ustawiony .

${1+"$@"}Rozwija się więc "$@"tylko do funkcji $1set ( $# > 0), która działa wokół tego ograniczenia powłoki Bourne'a.

Zauważ, że powłoka Bourne'a jest jedyną powłoką z tym problemem. Nowoczesne shs (które są shzgodne ze specyfikacją POSIX sh(której nie ma powłoka Bourne'a)) nie mają tego problemu. Potrzebujesz tego tylko wtedy, gdy potrzebujesz kodu do pracy na bardzo starych systemach, w których /bin/shmoże być powłoką Bourne'a zamiast standardowej powłoki (zauważ, że POSIX nie określa lokalizacji standardu sh, więc na przykład w Solarisie przed Solaris 11, /bin/shnadal był powłoką Bourne'a (chociaż nie miał tego konkretnego problemu), podczas gdy normalny / standardowy shznajdował się w innej lokalizacji ( /usr/xpg4/bin/sh)).

Istnieje jednak problem na tej perlrunstronie perldoc, który $0nie jest cytowany.

Aby uzyskać więcej informacji, zobacz http://www.in-ulm.de/~mascheck/various/bourne_args/ .

Stéphane Chazelas
źródło
Nie można się rozmnażać w Heirloom. Prawdopodobnie nie dotyczy systemu Solaris.
ormaaj
2
@ormaaj. Tak, zobacz stronę, do której linkowałem. Zostało to naprawione w SVR3, a Solaris / SunOS powyżej 5 oparty na SVR4. I ta strona wspomina, że ​​4.1.x też nie miał problemu.
Stéphane Chazelas
O, rozumiem. <3 strony Mascheck.
ormaaj
3

Istnieje różnica między:

command ""

i

command

W jednym przekazujesz jeden argument, który jest pustym ciągiem. W drugim przypadku przekazano zero argumentów.

Dla obu, „$ @” będzie zbliżać się do tej samej rzeczy: "". Ale użycie ${1:+"$@"}byłoby ""pierwsze, a argumenty nie były przekazywane za drugim, co było celem.

Staje się to ważne, jeśli wykonujesz coś w skrypcie poniżej, zwanym sshwrapper, który wywołujesz za pomocą opcjonalnego polecenia lub bez argumentów w celu uzyskania interaktywnej powłoki.

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

Spowoduje to próbę uruchomienia „” na zdalnym hoście (który właśnie zwraca), nie byłby to interaktywna powłoka.

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

Uruchamia interaktywną powłokę na zdalnym hoście, ponieważ exec poprawnie interpretuje zmienną jako nic, a nie pusty ciąg.

Przeczytaj o użyciu „$ {parametr: + słowo}” („Użyj wartości alternatywnej”) i podobnych ciągów zmiennych zmiennych na stronach podręcznika bash.

Arcege
źródło
wydaje się, że dotyczy to tylko powłoki Bourne'a, a nie żadnej shimplementacji zgodnej z POSIX (patrz inna odpowiedź).
törzsmókus
4
Nie, ${1:+"$@"}rozwinąłby się do braku argumentu, gdyby $1był pusty. Chcesz ${1+"$@"}. Zasadniczo masz odwrócone.
Stéphane Chazelas,
0

Podsumowałem odpowiedź Stéphane'a Chazelasa:

  • $ {1: + „$ @”} test, jeśli 1 $ jest zerowy lub nieuzbrojony
  • Test {1 + „$ @”} ”, jeśli 1 USD jest rozbrojony

więc jeśli użyjesz drugiego z parametrem „”, oznacza to, że $ 1 jest zerowy, ale nie sprawdza, czy jest pusty, czy nie, po prostu widzi, że został już ustawiony, ale jest pusty czy nie, więc rozwinie się $ @ , ale używasz $ {1: + "$ @"} 'z „”, nie będzie się już rozwijał $@.

Kevin
źródło
7
To z pewnością podsumowano, choć może nie wyjaśnić ...
Archemar,