Що означає $ {1 + "$ @"} у сценарії оболонки, і чим він відрізняється від "$ @"?


43

У документації на Perl perlrun (1) пропонує запустити скрипти Perl за допомогою двомовної оболонки / заголовка Perl:

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

Що ${1+"$@"}означає? Я спробував використовувати "$@"натомість (використовуючи Bash як / bin / sh), і, здається, він працює так само добре.


Редагувати

Два відповіді нижче кажуть, що так і повинно бути ${1:+"$@"}. Мені відомо ${parameter:+word}синтаксис ("Використовувати альтернативне значення"), зафіксований у bash (1). Однак я непереконаний, бо

  1. І те, ${1+"$@"}і інше "$@"працює добре, навіть коли немає параметрів. Якщо я створю просто.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. Оболонка Борна була давньою оболонкою, яка вперше була випущена у версії 7 для Unix у 1979 році і все ще була поширеною до середини 90-х, як /bin/shу більшості комерційних Unices.

Це є предком більшості Bourne-подібних оболонок , як ksh, bashабо zsh.

Він мав кілька незручних особливостей, багато з яких було зафіксовано, kshа інші оболонки та нову стандартну специфікацію sh, одна з яких така:

За допомогою оболонки Bourne (принаймні тих варіантів, де вона не була виправлена): "$@"розширюється на один порожній аргумент, якщо список позиційних параметрів порожній ( $# == 0), а не аргумент взагалі.

${var+something}розширюється на "щось", якщо $varне встановлено. Це чітко зафіксовано у всіх оболонках, але важко знайти в bashдокументації, оскільки вам потрібно звернути увагу на це речення:

Не виконуючи розширення підрядків, використовуючи форми, задокументовані нижче, тестуйте bash для параметра, який не встановлений чи недійсний. Пропускання товстої кишки призводить до тестування лише для параметра, який не встановлений .

Так ${1+"$@"}розширюється до "$@"лише, якщо $1встановлено ( $# > 0), що працює навколо цього обмеження оболонки Борна.

Зауважте, що оболонка Bourne - єдина оболонка з цією проблемою. Сучасні shs (що shвідповідає специфікації POSIX sh(що оболонки Борна не є)) не мають цього питання. Тож вам потрібно лише те, що вам потрібен код для роботи в дуже старих системах, де /bin/shможе бути оболонка Bourne замість стандартної оболонки (зверніть увагу, що POSIX не визначає розташування стандарту sh, наприклад, на Solaris перед Solaris 11, /bin/shвсе ще був оболонкою Борна (хоча цього питання не виникало), коли нормальний / стандарт shбув в іншому місці ( /usr/xpg4/bin/sh)).

На цій perlrunсторінці perldoc є проблема, яка $0не цитується.

Для отримання додаткової інформації див. Http://www.in-ulm.de/~mascheck/various/bourne_args/ .


Не вдається відтворити в реєстрі. Напевно, не стосується Solaris.
ormaaj

2
@ormaaj. Так, дивіться сторінку, яку я пов’язав. Це було зафіксовано у SVR3, а Solaris / SunOS вище 5 переоснащено на SVR4. І ця сторінка згадує, що в 4.1.x також не було проблеми.
Стефан Шазелас

А, бачу. <3 сторінки Машека.
ormaaj

3

Існує різниця між:

command ""

і

command

В одному ви передаєте один аргумент, який є порожнім рядком. У другій передано нульові аргументи.

Для обох, «$ @» буде прирівнювати до того ж: "". Але використання ${1:+"$@"}було б ""для першого, і жодних аргументів не було передано для другого, що було наміром.

Це стає важливим, якщо ви робите щось із наведеного нижче сценарію, зване sshwrapper, яке ви викликаєте за допомогою додаткової команди або відсутні аргументи для отримання інтерактивної оболонки.

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

Це намагатиметься запустити "" на віддаленому хості (який просто повертається), це не буде інтерактивною оболонкою.

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

Запустив би інтерактивну оболонку на віддаленому хості, оскільки exec правильно інтерпретував змінну як нічого, а не порожню рядок.

Прочитайте про використання "$ {параметра: + word}" ("Використовувати альтернативне значення") та подібних рядків змінних розширень на сторінках керівництва bash.


це, мабуть, стосується лише оболонки Bourne, а не для будь-якої shреалізації, сумісної з POSIX (див. іншу відповідь).
törzsmókus

4
Ні, ${1:+"$@"}не розгорнувся б до жодного аргументу, якби він $1був порожнім. Ти хочеш ${1+"$@"}. В основному, ви це змінили.
Стефан Шазелас

0

Я підсумував відповідь Стефана Шазеласа:

  • $ {1: + "$ @"} "тест, якщо $ 1 недійсний або скасовано
  • $ {1 + "$ @"} "тест, якщо $ 1 не встановлено

тож якщо використовувати другий з параметром "", це означає, що $ 1 є нульовим, але він не перевіряє, чи він є нульовим, чи ні, він просто бачить, що він уже встановлений, все-таки він порожній чи ні, тому він розшириться $ @ , але ви використовуєте $ {1: + "$ @"} 'з "", вона більше не розширюватиметься $@.


7
Це, безумовно, підсумовано, хоча це може не з’ясувати ...
Архемар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.