Je m'attendais à ne pas obtenir de sortie.
Si nullglob
était la valeur par défaut, de nombreuses commandes se comporteraient de manière assez inattendue, car il est (peut-être malheureusement) courant que les commandes traitent le cas de zéro arguments de nom de fichier de manière qualitativement différente du cas de un ou plusieurs arguments de nom de fichier.
Supposez que vous ayez activé nullglob
(shopt -s nullglob
) et que vous vous trouviez dans un répertoire où aucun fichier ne correspond à *.txt
. Alors *.txt
se développera en effet en rien - non pas un champ vide, mais pas de champ du tout - comme vous le pensiez. Mais cela aurait ces résultats :
ls *.txt
listerait tous les fichiers dans le répertoire actuel (sauf les fichiers cachés), car c'est ce que fait ls
lorsque vous ne lui passez aucun argument de nom de fichier.
cat *.txt
lirait depuis l'entrée standard, car lorsque cat
n'a pas d'arguments de nom de fichier, il est comme si vous aviez exécuté cat -
. Si vous exécutez de manière interactive, il se met en attente d'une entrée. De nombreuses commandes se comportent ainsi.
cp *.txt dest/
échouerait avec l'erreur cp: opérande de fichier de destination manquante après 'dest/'
. Ce n'est pas une catastrophe, mais c'est déroutant et très différent du succès silencieux qui est probablement souhaité.
file *.txt
, et divers autres programmes sans comportement spécial pour le cas de zéro argument de nom de fichier, échoueraient toujours avec une erreur ou un message d'utilisation lorsqu'aucun n'est passé.
- Même les cas qui semblent intuitivement devoir fonctionner n'auraient souvent pas le résultat attendu.
printf 'Fichier obtenu : "%s"\n' *.txt
imprimerait Fichier obtenu : ""
au lieu de rien.
- L'omission accidentelle de citer les occurrences de
*
, ?
et [
qui ne sont pas censés être développés par le shell produirait plus souvent des résultats clairement erronés, mais de manière difficile à comprendre. Par exemple, si aucun nom de fichier dans le répertoire actuel ne commençait par gedit
, alors apt list gedit*
(où apt list 'gedit*'
était prévu) deviendrait simplement apt list
et listerait toutes les packages disponibles.
Il est donc bien que vous n'obteniez pas ce comportement sans le demander. Probablement la situation pratique la plus courante qui est effectivement simplifiée par nullglob
est pour f in *.txt
. Voir aussi cette question (à laquelle la réponse de Sergiy Kolodyazhnyy est liée).
La question plus difficile à répondre est pourquoi failglob
- où c'est une erreur d'expansion d'avoir un glob qui ne correspond à aucun fichier - n'est pas la valeur par défaut dans bash. Je crois que la réponse de Sergiy Kolodyazhnyy capture la raison cela même sans l'aborder directement. Conserver des globs non développés sans produire d'erreur d'expansion est (peut-être malheureusement) le comportement standardisé, et c'est aussi un comportement traditionnel, et donc attendu. Bien que bash ne tente pas d'être entièrement conforme à POSIX sauf s'il est invoqué avec le nom sh
ou passe l'option --posix
, bon nombre de ses choix de conception même en dehors du mode POSIX suivent directement POSIX. Ils devaient choisir un comportement, et il y a des inconvénients associés à aller à l'encontre des attentes des utilisateurs.
Je pense que c'est l'aspect le moins historiquement influent de la question, c'est pourquoi je l'ai laissé pour la fin... mais il vaut la peine de mentionner qu'il y a quelque chose de conceptuellement étrange dans le comportement de nullglob
.
nullglob
semble élégant au premier abord car, syntaxiquement, il ne traite pas différemment le cas de zéro fichiers correspondants du cas de un, deux, ou de tout autre nombre. Les commandes que nous exécutons, en arguments auxquelles se développent les globs, ne tendent pas à les traiter de la même manière, comme détaillé ci-dessus. Mais syntaxiquement, cela semble au moins correct, ce qui je pense est la motivation de votre question.
Et pourtant, il y a une autre incohérence, plus subtile, que nullglob
ne résout pas - qu'elle amplifie même. Le cas de zéro caractères de glob ("jokers") est traité de manière profondément différente de celui de un, ou deux, ou de tout autre nombre. Par exemple, avec shopt -s nullglob
, si ab?d?f
ne correspond à aucun fichier, il est supprimé ; si ab?d
ne correspond à aucun fichier, il est supprimé ; mais si ab
ne correspond à aucun fichier (c'est-à-dire s'il n'y a pas de fichier dont le nom est exactement ab
), il n'est toujours pas supprimé. Bien sûr, ce serait une catastrophe s'il était supprimé, car il se peut qu'il ne soit pas censé faire référence à un fichier existant dans le répertoire actuel du tout ; il pourrait même ne pas faire référence à un fichier. Mais cela élimine tout espoir de cohérence totale.
Les trois comportements que bash offre - le comportement par défaut de traiter les globs qui ne correspondent à aucun fichier comme s'ils n'étaient pas des globs et de les transmettre non développés, le comportement que vous attendiez de les traiter (si vous permettez ce tour de phrase étrange) comme signifiant les zéro des fichiers qui correspondent (nullglob
), et le comportement sûr de les considérer comme des erreurs (failglob
) - représentent tous des approches différentes de l'ambiguïté inhérente au shell qui ne peut pas savoir si un mot donné est destiné à être un nom de fichier. Le shell effectue ses expansions sans savoir comment les commandes particulières que vous appelez avec lui vont traiter leurs arguments.
C'est l'un des nombreux exemples de séparation des préoccupations. Dans les systèmes dont la conception suit la philosophie Unix, chaque partie est censée faire une chose et la faire bien. Le shell traite le texte en commandes et arguments et invoque ces commandes, la plupart desquelles sont externes au shell lui-même. Cela a tendance à être beaucoup plus agréable et plus polyvalent que les systèmes où les commandes externes sont elles-mêmes responsables de réaliser ces transformations (comme avec les processeurs de commandes traditionnels dans DOS et Windows). Mais cela a ses inconvénients occasionnels.