Я обнаружил, что установка 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
будет выполнен.