La parentesi funziona nella shell bash stessa, ma non nello script bash


11

Posso eseguire questo comando dal mio prompt della riga di comando:

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

Copia ricorsivamente tutto il contenuto di folder tranne la sottodirectory indicata exclude-menella directory corrente. Funziona esattamente come previsto. Tuttavia, ho bisogno di questo per funzionare in uno script bash che ho scritto, dove ho questo:

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

Ma quando eseguo lo script:

bash my-script.sh

Capisco questo:

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

E non riesco a capire perché funzioni dal prompt dei comandi, ma la stessa identica riga non funziona in uno script bash.

Risposte:


11

Questo perché la sintassi che stai usando dipende da una particolare funzione bash che non è attivata di default per shell non interattive (script). Puoi attivarlo aggiungendo il comando pertinente al tuo script:

## Enable extended globbing features
shopt -s extglob

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

Questa è la sezione pertinente di 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

Questa è la seconda volta che trovo questa risposta (sì, brutta memoria). Questa volta ho provato a mettere in esecuzione env > file1lo script ed eseguirlo ./it, e poi env > file2e source it, nella speranza che avrei trovato una differenza nella envs, che non è il caso. Come posso elencare a livello di programmazione tutta la differenza tra due shell (in questo caso interattivo vs non interattivo)?
Enrico Maria De Angelis,


2

Aggiungi questa riga nella parte superiore dello script:

shopt -s extglob

!(...)è una funzione di corrispondenza dei motivi estesa, è necessario extglobabilitare l'opzione per usarla. Vedi shopt builtin per maggiori dettagli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.