O parêntese funciona no próprio shell bash, mas não no script bash

11

Eu posso executar este comando no meu prompt de linha de comando:

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

Copiar recursivamente todo o conteúdo, folder exceto o subdiretório nomeado exclude-meno diretório atual. Isso funciona exatamente como pretendido. No entanto, eu preciso que isso funcione em um script bash que eu escrevi, onde eu tenho o seguinte:

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

Mas quando eu executo o script:

bash my-script.sh

Eu entendi isso:

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

E não sei por que ele funciona no prompt de comando, mas a mesma linha exata não funciona em um script bash.

nzifnab
fonte

Respostas:

11

Isso ocorre porque a sintaxe que você está usando depende de um recurso específico do bash que não é ativado por padrão para shells (scripts) não interativos. Você pode ativá-lo adicionando o comando relevante ao seu script:

## Enable extended globbing features
shopt -s extglob

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

Esta é a seção relevante de 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
terdon
fonte
Esta é a segunda vez que encontro essa resposta (sim, memória ruim). Desta vez, tentei rodar env > file1no script e execute ./it, e então env > file2e source it, na esperança de que eu tivesse encontrado uma diferença no envs, o que não é o caso. Como posso listar programaticamente toda a diferença entre duas conchas (nesse caso, interativas versus não interativas)?
Enrico Maria De Angelis
2

Adicione esta linha na parte superior do seu script:

shopt -s extglob

!(...)é um recurso estendido de correspondência de padrões, é necessário extglobativar a opção. Veja shopt builtin para mais detalhes.

cuonglm
fonte