Nella maggior parte delle shell nullglob
non è l'impostazione predefinita. Ciò significa, ad esempio, se esegui questo comando
ls *
in una directory vuota, espanderà il *
glob in un letterale *
, invece di un elenco vuoto di argomenti. Ci sono modi per cambiare questo comportamento, in modo che *
in una directory vuota restituirà una lista vuota di argomenti, che sembrerebbe più intuitiva.
Quindi, c'è un motivo per cui nullglob
è disabilitato di default? Se sì, qual è il motivo?
Risposta accettata:
Il nullglob
opzione (che BTW è un zsh
invenzione, aggiunta solo anni dopo a bash
(2.0
)) non sarebbe l'ideale in un certo numero di casi. E ls
è un buon esempio:
ls *.txt
O il suo equivalente più corretto:
ls -- *.txt
Con nullglob
on eseguirebbe ls
senza argomenti trattati 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 utilità di testo:
grep foo *.txt
Cercherei foo
su stdin se non è presente txt
file.
Un'impostazione predefinita più ragionevole, e quella 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 un failglob
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 (sebbene ciò debba cambiare in 4.4), quell'opzione, se 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 è necessario che tutti i glob non corrispondano per annullare il comando. Ad esempio, se esiste un file txt e nessun file html, diventa:
ls -- file.txt
Puoi ottenere quel comportamento con zsh
con setopt cshnullglob
sebbene sia un modo più sensato per farlo in zsh
sarebbe usare un glob come:
ls -- *.(txt|html)
In zsh
e ksh93
, puoi anche applicare nullglob su base globale, 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 c'è txt
file invece di fallire il comando con un errore (o renderlo un array con un *.txt
argomento letterale con altre shell).
Versioni di fish
prima della 2.3 funzionava come bash -O nullglob
ma dai un avviso quando interattivo quando un glob non ha corrispondenze. Dalla 2.3 funziona come zsh
fatta eccezione per i glob usati in for
, set
o count
.
Ora, nella nota sulla cronologia, il comportamento era effettivamente interrotto dalla conchiglia Bourne. Nelle versioni precedenti di Unix, il globbing veniva eseguito tramite il /etc/glob
helper e quell'helper si sono comportati come csh
:fallirebbe il comando se nessuno dei glob corrispondesse a nessun file e rimuoverebbe i glob senza corrispondenze in caso contrario.
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) è stata fornita con un'altra nuova funzionalità Unix:l'ambiente. Ciò significava espansione delle variabili (il suo predecessore aveva solo $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 (possibilmente per la compatibilità con le versioni precedenti della shell Thompson dove echo $1
invocherebbe comunque /etc/glob
se $1
conteneva caratteri jolly (era più simile all'espansione della macro del pre-processore, poiché nel valore espanso veniva nuovamente analizzato come codice shell)).
Il fallimento dei glob che non corrispondono significherebbe, 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 il globbing su espansione variabile) in quel caso non riesce il comando (e direi che è meglio che lasciare un bug dormiente lì, anche se non è buono come non eseguire affatto il globbing come in zsh
).