Come sfuggire estesi modelli di espansione di percorso nelle espressioni citate?
-
22-08-2019 - |
Domanda
In aggiunta ai modelli di base *
, ?
e [...]
, la shell Bash fornisce modello esteso corrispondenza operatori come !(pattern-list)
( "corrispondenti tutti tranne uno dei pattern dati"). L'opzione di shell extglob
deve essere impostato per usarli. Un esempio:
~$ mkdir test ; cd test ; touch file1 file2 file3
~/test$ echo *
file1 file2 file3
~/test$ shopt -s extglob # make sure extglob is set
~/test$ echo !(file2)
file1 file3
Se passo un'espressione shell di un programma che esegue in una sotto-shell, l'operatore causa un errore. Ecco un test che viene eseguito direttamente un sub-shell (qui sto eseguendo da un'altra directory per assicurarsi che l'espansione non accade prematuramente):
~/test$ cd ..
~$ bash -c "cd test ; echo *"
file1 file2 file3
~$ bash -c "cd test ; echo !(file2)" # expected output: file1 file3
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
Ho provato tutti i tipi di fuggire, ma niente mi è venuta in mente ha funzionato correttamente. Ho anche sospettato extglob
non è impostato in una sotto-shell, ma non è questo il caso:
~$ bash -c "shopt -s extglob ; cd test ; echo !(file2)"
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
Qualsiasi soluzione apprezzato!
Soluzione
$ bash -O extglob -c 'echo !(file2)' file1 file3
Altri suggerimenti
bash analizza ogni riga prima di eseguirlo, così "shopt -s extglob" non hanno avuto effetto quando bash sta convalidando la sintassi modello globbing. L'opzione non può essere attivata sulla stessa linea. Ecco perché la soluzione "bash -O extglob -c 'xyz'" (da Randy Proctor) funziona ed è necessario.
Ecco un altro modo, se si vuole evitare eval
ed è necessario essere in grado di trasformare extglob e spegnimento all'interno della subshell. Basta mettere il vostro modello in una variabile:
bash -c 'shopt -s extglob; cd test; patt="!(file2)"; echo $patt; shopt -u extglob; echo $patt'
dà questo output:
file1 file3
!(file2)
extglob è stata inserita o disinserita. Se il primo ha avuto echo
citazioni intorno al $patt
, sarebbe solo sputare il modello come la seconda echo
(che probabilmente dovrebbe avere le virgolette).
Beh, non ho alcuna vera experince con extglob , ma posso farlo funzionare avvolgendo il echo
in un eval
:
$ bash -c 'shopt -s extglob ; cd test ; eval "echo !(file2)"'
file1 file3