Вопрос или проблема
Я пытался скопировать локальный каталог с исключениями в другое место в сценарии Bash и постоянно получал сообщение об ошибке синтаксиса. Я в конце концов создал минимальный пример, который воспроизводит мою проблему… что происходит только из функции.
Итак, это работает, как и ожидалось:
#!/usr/bin/env bash
rm -rf /tmp/adir/ && mkdir --parents /tmp/adir/
shopt -s extglob dotglob
cp -ar /some/dir/subdirectory/!(tests|.git) /tmp/adir/
shopt -u extglob dotglob
…но это не работает:
#!/usr/bin/env bash
a_function() {
rm -rf /tmp/adir && mkdir --parents /tmp/adir
shopt -s extglob dotglob
cp -ar /some/dir/subdirectory/!(tests|.git) /tmp/adir
shopt -u extglob dotglob
}
a_function
Второй вариант выдает ошибку синтаксиса:
./test.sh: line 6: syntax error near unexpected token `('
./test.sh: line 6: ` cp -ar /some/dir/subdirectory/!(tests|.git) /tmp/adir/'
Версия Bash: GNU bash, version 5.2.15(1)-release (x86_64-pc-linux-gnu)
Надеюсь, кто-то сможет помочь.
Параметр extglob
должен быть установлен не только в строке, где он используется, но и в месте, где функция объявляется.
См. https://stackoverflow.com/q/65533232/1030675 для аналогичного вопроса и подробного ответа.
.
Ответ или решение
Необычное поведение функции Bash: Разбор проблем с extglob
При работе с Bash-скриптами иногда возникают специфические проблемы, которые могут вызвать путаницу. Одной из распространенных ситуаций является использование специального расширения шаблонов extglob
, которое позволяет делать более гибкие сопоставления файлов и каталогов. Рассмотрим детально проблему, которая возникла при использовании extglob
внутри функции Bash.
Проблема
Ваша проблема заключается в том, что при попытке выполнить команду копирования с использованием extglob
внутри функции возникает синтаксическая ошибка. Ниже приведен минимальный пример, который демонстрирует эту ситуацию:
#!/usr/bin/env bash
a_function() {
rm -rf /tmp/adir && mkdir --parents /tmp/adir
shopt -s extglob dotglob
cp -ar /some/dir/subdirectory/!(tests|.git) /tmp/adir
shopt -u extglob dotglob
}
a_function
Ошибка, которую вы получаете, выглядит следующим образом:
./test.sh: line 6: syntax error near unexpected token `('
./test.sh: line 6: ` cp -ar /some/dir/subdirectory/!(tests|.git) /tmp/adir'
Причины проблемы
Суть проблемы заключается в том, что опции, такие как extglob
, должны быть установлены не только во время выполнения команды, но и в контексте определения функции. Когда вы вызываете a_function
, опции, активированные внутри функции, не действуют в контексте самого вызова функции, если они не были активированы заранее.
Решение
Для того чтобы ваше скриптовое решение работало должным образом, необходимо убедиться, что shopt
устанавливается в области видимости, где вызывается функция. Вот несколько вариантов, как это можно реализовать:
-
Установка
shopt
перед вызовом функции:Вы можете просто установить
shopt
вне функции, прежде чем вызывать её:#!/usr/bin/env bash shopt -s extglob dotglob a_function() { rm -rf /tmp/adir && mkdir --parents /tmp/adir cp -ar /some/dir/subdirectory/!(tests|.git) /tmp/adir } a_function shopt -u extglob dotglob
-
Использование
shopt
внутри функции:Если вы хотите, чтобы опция действовала только внутри функции, вы можете сделать следующее:
#!/usr/bin/env bash a_function() { shopt -s extglob dotglob rm -rf /tmp/adir && mkdir --parents /tmp/adir cp -ar /some/dir/subdirectory/!(tests|.git) /tmp/adir shopt -u extglob dotglob } a_function
-
Комбинация подходов:
Можно также комбинировать оба подхода, чтобы минимизировать риски и не оставлять
extglob
включённым во всем скрипте.
Заключение
Проблема с синтаксической ошибкой в вашем Bash-скрипте возникла из-за недостаточной области видимости активации extglob
. Понимание особенностей работы функций Bash и механизмов активации расширенных глобов позволит вам избегать подобных ошибок в будущем. С помощью описанных выше решений вы сможете корректно реализовать функциональность, чтобы избежать неожиданных результатов при запуске ваших скриптов.