Как избежать шаблонов расширения расширенного имени пути в выражениях в кавычках?
-
22-08-2019 - |
Вопрос
В дополнение к основному *
, ?
и [...]
шаблоны, оболочка Bash предоставляет расширенные операторы сопоставления шаблонов, такие как !(pattern-list)
(«соответствует всем, кроме одного из заданных шаблонов»).А extglob
Для их использования необходимо установить параметр оболочки.Пример:
~$ mkdir test ; cd test ; touch file1 file2 file3
~/test$ echo *
file1 file2 file3
~/test$ shopt -s extglob # make sure extglob is set
~/test$ echo !(file2)
file1 file3
Если я передаю выражение оболочки программе, которая выполняет его в подоболочке, оператор вызывает ошибку.Вот тест, который запускает субоболочку напрямую (здесь я выполняю из другого каталога, чтобы убедиться, что расширение не произойдет преждевременно):
~/test$ cd ..
~$ bash -c "cd test ; echo *"
file1 file2 file3
~$ bash -c "cd test ; echo !(file2)" # expected output: file1 file3
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
Я пробовал все способы побега, но ничего из того, что я придумал, не сработало правильно.я тоже подозревал extglob
не установлен в подоболочке, но это не так:
~$ bash -c "shopt -s extglob ; cd test ; echo !(file2)"
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
Любое решение приветствуется!
Решение
$ bash -O extglob -c 'echo !(file2)' file1 file3
Другие советы
bash анализирует каждую строку перед ее выполнением, поэтому команда "shop -s extglob" не подействует, когда bash проверяет синтаксис шаблона подстановки.Опцию нельзя включить в одной строке.Вот почему решение «bash -O extglob -c 'xyz» (от Рэнди Проктора) работает и требуется.
Вот еще один способ, если вы хотите избежать eval
и вам нужно уметь поворачивать extglob включаться и выключаться внутри подоболочки.Просто поместите свой шаблон в переменную:
bash -c 'shopt -s extglob; cd test; patt="!(file2)"; echo $patt; shopt -u extglob; echo $patt'
дает этот вывод:
file1 file3
!(file2)
демонстрируя это extglob был установлен и отключен.Если первый echo
были кавычки вокруг $patt
, он просто выдаст шаблон, подобный второму echo
(который, вероятно, должен иметь кавычки).
Ну, у меня нет реального опыта работы с extglob, но я могу заставить его работать, обернув echo
в eval
:
$ bash -c 'shopt -s extglob ; cd test ; eval "echo !(file2)"'
file1 file3