L' nullglob
opzione (che BTW è zsh
un'invenzione, aggiunta solo anni dopo a bash
( 2.0
)) non sarebbe l'ideale in un numero di casi. Ed ls
è un buon esempio:
ls *.txt
O il suo equivalente più corretto:
ls -- *.txt
Con nullglob
on verrebbe eseguito ls
senza alcun argomento che viene trattato come ls -- .
(elenca la directory corrente) se nessun file corrisponde, il che è probabilmente peggio che chiamare ls
con un letterale *.txt
come argomento.
Avresti problemi simili con la maggior parte delle utility di testo:
grep foo *.txt
Sarebbe cercare foo
su stdin se non c'è txt
il file.
Un default più sensato, e quello di csh, tcsh, zsh o fish 2.3+ (e delle prime shell Unix) è annullare del tutto il comando se il glob non corrisponde.
bash
(dalla versione 3) ha failglob
un'opzione per questo (interessante per questa discussione, poiché contrariamente a ash
, AT&T ksh
o zsh
, bash
non supporta gli ambiti locali per le opzioni (anche se questo è cambiare in 4.4), quell'opzione quando abilitata a livello globale interrompe alcune cose come le funzioni di completamento bash).
Nota che csh e tcsh sono leggermente diversi da zsh
, fish
o bash -O failglob
in casi come:
ls -- *.txt *.html
Dove sono necessari tutti i globs per non corrispondere affinché il comando venga annullato. Ad esempio, se esiste un file txt e nessun file html, questo diventa:
ls -- file.txt
È possibile ottenere che il comportamento con zsh
con setopt cshnullglob
se un modo più sensato di farlo in zsh
sarebbe quello di utilizzare un glob come:
ls -- *.(txt|html)
In zsh
e ksh93
, puoi anche applicare nullglob su base per-glob, che è un approccio molto più sano rispetto alla modifica di un'impostazione globale:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
creerebbe un array vuoto se non ci sono txt
file invece di fallire il comando con un errore (o renderlo un array con un *.txt
argomento letterale con altre shell).
Le versioni fish
precedenti alla 2.3 funzionerebbero come bash -O nullglob
ma darebbero un avvertimento quando interattivo quando un glob non ha corrispondenza. Dal 2.3, funziona come zsh
tranne per i globs usati in for
, set
o count
.
Ora, sulla nota della storia, il comportamento è stato effettivamente rotto dalla shell Bourne. Nelle versioni precedenti di Unix, il globbing veniva eseguito tramite l' /etc/glob
helper e quell'helper si comportava in modo simile csh
: avrebbe fallito il comando se nessuno dei glob avesse corrispondenza con qualsiasi file e avrebbe rimosso i globs senza alcuna corrispondenza.
Quindi la situazione in cui ci troviamo oggi è dovuta a una decisione sbagliata presa nella shell Bourne.
Si noti che la shell Bourne (e la shell C) è arrivata con un'altra nuova funzionalità Unix: l'ambiente. Ciò significava espansione variabile (il suo predecessore aveva solo i $1
, $2
... parametri posizionali). La shell Bourne ha anche introdotto la sostituzione dei comandi.
Un'altra cattiva decisione di progettazione della shell Bourne è stata quella di eseguire il globbing (e la divisione) sull'espansione delle variabili e la sostituzione dei comandi (probabilmente per la compatibilità con le versioni precedenti della shell Thompson dove echo $1
sarebbe comunque invocare /etc/glob
se $1
contenesse caratteri jolly (era più simile all'espansione macro pre-processore) lì, come nel valore espanso è stato nuovamente analizzato come codice shell)).
I globs non corrispondenti che non corrispondono significherebbero ad esempio che:
pattern='a.*b'
grep $pattern file
fallirebbe il comando (a meno che non ci siano alcuni a.whateverb
file nella directory corrente). csh
(che esegue anche globbing in caso di espansione variabile) in quel caso fallisce il comando (e direi che è meglio che lasciare un bug dormiente lì, anche se non è buono come non fare globbing come in zsh
).