Установка параметров bash в составной команде

Установка параметров bash в составной команде

Я обнаружил, что установка extglobпараметра оболочки только внутри составного соединения приводит к сбою последующих расширенных glob. Требуется ли устанавливать параметры оболочки вне составных команд? Я не видел указаний на такое требование в man-страницах Bash.

Например, следующий скрипт работает нормально (выводит a.0 a.1):

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
shopt -s extglob
ls "a."!(b*)

Однако если последние две строки выполнить как составную команду, скрипт завершится со следующей ошибкой:

syntax error near unexpected token `('
`    ls "a."!(b*)'

Это было протестировано с использованием версий Bash от 4.2 до 4.4 и с различнымисоставные команды:

(1) условный --if

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
if true; then
    shopt -s extglob
    ls "a."!(b*)
fi

(2) подтяжки --{ }

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
{
    shopt -s extglob
    ls "a."!(b*)
}

(3) подоболочка -- ( ):

#!/bin/bash
touch a.0   a.1 \
      a.b.0 a.b.1
(
    shopt -s extglob
    ls "a."!(b*)
)

Во всех случаях, если shoptперемещается за пределы составной команды, скрипт выполняется успешно.

решение1

Ни одна часть составной команды не выполняется до тех пор, пока не будет проанализирована вся команда, что косвенно задокументировано вОперация «Шелл»раздел руководства: вся токенизация и разбор происходят до выполнения команды "the". Включение extglobизменяет синтаксис языка, добавляя новые операторы сопоставления с шаблоном, которые распознаются во время токенизации.

Поскольку shoptна момент !(достижения команда не была выполнена, она рассматривается либо как попытка расширения истории ( !), либо как оператор управления (, а не !(как отдельный элемент (то же самое относится к @(, и т. д., за исключением того, что здесь нет расширения истории).

Когда синтаксический анализ достигает этого токена, в любом случае обычно возникает ошибка, хотя !(...)в начале строки или после нее timeнаходится инвертированный конвейер подоболочки. " unexpected token `('" означает, что в этом месте не удалось принять выражение подоболочки.

Это немного раздражает, когда вы хотите, чтобы extglob был включен только временно в подоболочке. Один из обходных путей — определить функцию, которая использует нужный вам glob, затем снова отключить extglob изатемвызовите функцию из подоболочки с включенным extglob:

shopt -s extglob
f() { ls "a."!(b*) ; }
shopt -u extglob
(
    shopt -s extglob
    f
)

Это очень неуклюже.


Тот же эффект происходит, если вы создаете псевдоним внутри составной команды, поскольку они также обрабатываются перед синтаксическим анализом:

if true
then
    alias foo=echo
    foo bar
fi
foo xyz

напечатает foo: command not found, а затем xyz, поскольку псевдонимявляетсясоздан, но недоступен до тех пор, пока не ifбудет выполнен.

Связанный контент