La parenthèse fonctionne dans le shell bash lui-même, mais pas dans le script bash

11

Je peux exécuter cette commande à partir de mon invite de ligne de commande:

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

Pour copier récursivement tout le contenu de l' folder exception du sous-répertoire nommé exclude-medans le répertoire courant. Cela fonctionne exactement comme prévu. Cependant, j'ai besoin de cela pour travailler dans un script bash que j'ai écrit, où j'ai ceci:

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

Mais quand j'exécute le script:

bash my-script.sh

J'ai compris:

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

Et je ne sais pas pourquoi cela fonctionne à partir de l'invite de commande, mais la même ligne exacte ne fonctionne pas dans un script bash.

nzifnab
la source

Réponses:

11

En effet, la syntaxe que vous utilisez dépend d'une fonctionnalité bash particulière qui n'est pas activée par défaut pour les shells (scripts) non interactifs. Vous pouvez l'activer en ajoutant la commande appropriée à votre script:

## Enable extended globbing features
shopt -s extglob

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

Il s'agit de la section pertinente 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
la source
C'est la deuxième fois que je trouve cette réponse (oui, mauvaise mémoire). Cette fois, j'ai essayé de mettre run env > file1dans le script et de l'exécuter ./it, puis env > file2et source it, dans l'espoir que j'aurais trouvé une différence dans le envs, ce qui n'est pas le cas. Comment puis-je lister par programme toute la différence entre deux shells (dans ce cas interactif vs non interactif)?
Enrico Maria De Angelis
2

Ajoutez cette ligne en haut de votre script:

shopt -s extglob

!(...)est une fonction de correspondance de motifs étendue, vous devez extglobactiver l'option pour l'utiliser. Voir shopt builtin pour plus de détails.

cuonglm
la source