Dans la plupart des shells nullglob
n'est pas la valeur par défaut. Cela signifie, par exemple, si vous exécutez cette commande
ls *
dans un répertoire vide, il développera le *
glob en un *
littéral , à la place d'une liste vide d'arguments. Il existe des moyens de modifier ce comportement, de sorte que *
dans un répertoire vide renverra une liste vide d'arguments, ce qui semblerait plus intuitif.
Alors, y a-t-il une raison pour laquelle nullglob
est désactivé par défaut ? Si oui, quelle est cette raison ?
Réponse acceptée :
Le nullglob
option (dont BTW est un zsh
invention, ajoutée seulement des années plus tard à bash
(2.0
)) ne serait pas idéal dans un certain nombre de cas. Et ls
est un bon exemple :
ls *.txt
Ou son équivalent plus correct :
ls -- *.txt
Avec nullglob
on exécuterait ls
sans argument qui est traité comme ls -- .
(liste le répertoire courant) si aucun fichier ne correspond, ce qui est probablement pire que d'appeler ls
avec un *.txt
littéral comme argument.
Vous auriez des problèmes similaires avec la plupart des utilitaires de texte :
grep foo *.txt
Rechercherait foo
sur stdin s'il n'y a pas de txt
fichier.
Une valeur par défaut plus raisonnable, et celle de csh, tcsh, zsh ou fish 2.3+ (et des premiers shells Unix) est d'annuler complètement la commande si le glob ne correspond pas.
bash
(depuis la version 3) a un failglob
option pour cela (intéressant pour cette discussion, car contrairement à ash
, AT&T ksh
ou zsh
, bash
ne prend pas en charge les étendues locales pour les options (bien que cela doive changer dans 4.4), cette option, lorsqu'elle est activée globalement, casse certaines choses comme les fonctions bash-completion).
Notez que csh et tcsh sont légèrement différents de zsh
, fish
ou bash -O failglob
dans des cas comme :
ls -- *.txt *.html
Où vous avez besoin que tous les globs ne correspondent pas pour que la commande soit annulée. Par exemple, s'il y a un fichier txt et aucun fichier html, cela devient :
ls -- file.txt
Vous pouvez obtenir ce comportement avec zsh
avec setopt cshnullglob
bien qu'une manière plus sensée de le faire en zsh
serait d'utiliser un glob comme :
ls -- *.(txt|html)
En zsh
et ksh93
, vous pouvez également appliquer nullglob sur une base globale, ce qui est une approche beaucoup plus sensée que la modification d'un paramètre global :
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
créerait un tableau vide s'il n'y avait pas de txt
fichier au lieu d'échouer la commande avec une erreur (ou d'en faire un tableau avec un *.txt
argument littéral avec d'autres shells).
Versions de fish
avant 2.3 fonctionnerait comme bash -O nullglob
mais donner un avertissement lorsqu'il est interactif lorsqu'un glob n'a pas de correspondance. Depuis la 2.3, cela fonctionne comme zsh
sauf pour les globs utilisés dans for
, set
ou count
.
Maintenant, sur la note d'historique, le comportement était en fait cassé par l'obus Bourne. Dans les versions précédentes d'Unix, le globbing se faisait via le /etc/glob
helper et que helper s'est comporté comme csh
:il échouerait la commande si aucun des globs ne correspondait à aucun fichier et supprimerait les globs sans correspondance sinon.
La situation dans laquelle nous nous trouvons aujourd'hui est donc due à une mauvaise décision prise dans le shell Bourne.
Notez que le shell Bourne (et le shell C) est venu avec une autre nouvelle fonctionnalité Unix :l'environnement. Cela signifiait une expansion variable (son prédécesseur n'avait que le $1
, $2
… paramètres de position). Le shell Bourne a également introduit la substitution de commandes.
Une autre mauvaise décision de conception du shell Bourne était d'effectuer le globbing (et le fractionnement) lors de l'expansion des variables et de la substitution de commandes (éventuellement pour une compatibilité descendante avec le shell Thompson où echo $1
invoquerait toujours /etc/glob
si $1
contenait des caractères génériques (cela ressemblait plus à une extension de macro de préprocesseur, car la valeur étendue était à nouveau analysée en tant que code shell)).
Des globs défaillants qui ne correspondent pas signifieraient par exemple que :
pattern='a.*b'
grep $pattern file
échouerait la commande (sauf s'il y a des a.whateverb
fichiers dans le répertoire courant). csh
(qui effectue également le globbing lors de l'expansion des variables) échoue la commande dans ce cas (et je dirais que c'est mieux que de laisser un bogue dormant là-bas, même si ce n'est pas aussi bon que de ne pas faire de globbing du tout comme dans zsh
).