El paréntesis funciona en el shell bash, pero no en el script bash

11

Puedo ejecutar este comando desde mi línea de comando:

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

Copiar recursivamente todos los contenidos, folder excepto el subdirectorio nombrado exclude-meen el directorio actual. Esto funciona exactamente como se pretendía. Sin embargo, necesito que esto funcione en un script bash que he escrito, donde tengo esto:

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

Pero cuando ejecuto el script:

bash my-script.sh

Entiendo esto:

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

Y no sé por qué funciona desde el símbolo del sistema, pero exactamente la misma línea no funciona en un script bash.

nzifnab
fuente

Respuestas:

11

Esto se debe a que la sintaxis que está utilizando depende de una característica de bash particular que no está activada por defecto para shells no interactivos (scripts). Puede activarlo agregando el comando relevante a su script:

## Enable extended globbing features
shopt -s extglob

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

Esta es la sección 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
fuente
Esta es la segunda vez que encuentro esta respuesta (sí, mala memoria). Esta vez traté de ejecutar env > file1en el script y ejecutar ./it, y luego env > file2y source it, con la esperanza de que hubiera encontrado una diferencia en el envs, que no es el caso. ¿Cómo puedo enumerar programáticamente todas las diferencias entre dos shells (en este caso, interactivas versus no interactivas)?
Enrico Maria De Angelis
2

Agregue esta línea cerca de la parte superior de su script:

shopt -s extglob

!(...)es una característica extendida de coincidencia de patrones, necesita la extglobopción habilitar para usarla. Ver shopt incorporado para más detalles.

Cuonglm
fuente