Круглая скобка работает в самой оболочке bash, но не в сценарии bash

11

Я могу запустить эту команду из командной строки:

cp -r folder/!(exclude-me) ./

Чтобы рекурсивно скопировать все содержимое, folder кроме подкаталога, названного exclude-meв текущий каталог. Это работает точно так, как задумано. Тем не менее, мне нужно, чтобы это работало в скрипте bash, который я написал, где у меня есть это:

if [ -d "folder" ]; then
  cp -r folder/!(exclude-me) ./
  rm -rf folder
fi

Но когда я запускаю скрипт:

bash my-script.sh

Я получаю это:

my-script.sh: line 30: syntax error near unexpected token `('
my-script.sh: line 30: `  cp -r folder/!(exclude-me) ./'

И я в растерянности относительно того, почему это работает из командной строки, но точно такая же строка не работает в скрипте bash.

nzifnab
источник

Ответы:

11

Это связано с тем, что используемый вами синтаксис зависит от конкретной функции bash, которая не активируется по умолчанию для неинтерактивных оболочек (сценариев). Вы можете активировать его, добавив соответствующую команду в ваш скрипт:

## Enable extended globbing features
shopt -s extglob

if [ -d "folder" ]; then
  cp -r folder/!(exclude-me) ./
  rm -rf folder
fi

Это соответствующий раздел man bash:

   If the extglob shell option is enabled using the shopt builtin, several
   extended  pattern  matching operators are recognized.  In the following
   description, a pattern-list is a list of one or more patterns separated
   by a |.  Composite patterns may be formed using one or more of the fol
   lowing sub-patterns:

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns
Тердон
источник
Это второй раз, когда я нахожу этот ответ (да, плохая память). На этот раз попытался поставить run env > file1в скрипт и выполнить ./it, а затем env > file2и source it, в надежде, что я бы нашел разницу в envs, что не так. Как я могу программно перечислить все различия между двумя оболочками (в данном случае интерактивные и неинтерактивные)?
Энрико Мария Де Анжелис
2

Добавьте эту строку в верхней части вашего скрипта:

shopt -s extglob

!(...)это расширенная функция сопоставления с шаблоном, для ее использования вам нужно extglobвключить опцию. Смотрите Shopt Builtin для более подробной информации.

cuonglm
источник