Je jouais avec l'expansion et j'ai remarqué un comportement particulier. J'ai essayé de faire:
echo ./*.txt
Et je n'avais aucun fichier .txt dans mon répertoire actuel. La sortie que j'ai obtenue était:
./*.txt
Je suis juste curieux: pourquoi ai-je eu ça? Je m'attendais à ne pas obtenir de sortie.
PS: Quand j'avais un .txt
fichier, l'expansion était correctement interprétée. En d'autres termes, disons que j'avais un fichier smthn.txt
, l'écho a effectivement fait écho current_directory/smthn.txt
.
la source
shopt -s nullglob
produira des chaînes vides pour des modèles inégalés etshopt -u nullglob
(réglage standard) produira le modèle lui-même.Si
nullglob
c'é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 argument de nom de fichier d'une manière qualitativement différente de celle d' un ou plusieurs arguments de nom de fichier.Supposons que vous ayez activé
nullglob
(shopt -s nullglob
) et que vous vous trouviez dans un répertoire où aucun fichier ne correspond*.txt
. Ensuite, il*.txt
s'agira en fait de rien - pas un champ vide, mais pas de champs du tout - comme vous vous y attendiez. Mais cela aurait ces résultats:ls *.txt
répertorierait tous les fichiers du répertoire actuel (à l'exception des fichiers masqués), car c'est ce qui sels
produit lorsque vous ne lui passez aucun argument de nom de fichier.cat *.txt
lirait à partir de l'entrée standard , car lorsqu'ilcat
n'a aucun argument de nom de fichier, c'est comme si vous couriezcat -
. S'il s'exécute de manière interactive, il attend en attente d'entrée. De nombreuses commandes se comportent de cette façon.cp *.txt dest/
échouerait avec l'erreurcp: missing destination file operand after 'dest/'
. Ce n'est pas un désastre, mais c'est déroutant et tout à fait différent du succès silencieux qui est probablement souhaité.file *.txt
, et divers autres programmes sans comportement spécial dans le cas d'arguments de nom de fichier zéro, échouaient toujours avec un message d'erreur ou d'utilisation quand aucun n'était transmis.printf 'Got file: "%s"\n' *.txt
imprimeraitGot file: ""
au lieu de rien.*
,?
et[
qui ne sont pas destinés à être élargi par le shell produirait plus souvent des résultats manifestement faux, mais d' une manière qui pourrait être difficile à comprendre. Par exemple, si aucun nom de fichier dans le répertoire courant ne commençait pargedit
, alorsapt list gedit*
(oùapt list 'gedit*'
c'était prévu) deviendrait justeapt list
et listerait tous les packages disponibles.Il est donc bon que vous n'obteniez pas ce comportement sans le demander. La situation pratique la plus courante qui est en fait simplifiée
nullglob
est probablementfor f in *.txt
. Voir aussi cette question (à laquelle la réponse de Sergiy Kolodyazhnyy est liée).La question la plus difficile à répondre est pourquoi -
failglob
où c'est une erreur d'extension 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 saisit la raison de cela même sans y répondre directement. Conserver des globes non expansifs sans produire une erreur d'expansion est (peut-être malheureusement) le comportement standardisé, et c'est aussi un comportement traditionnel, et donc attendu. Bien que bash n'essaie pas d'être entièrement compatible POSIX à moins qu'il ne soit appelé avec le nomsh
ou transmis l'--posix
option, bon nombre de ses choix de conception même lorsqu'il n'est pas en mode POSIX suivent directement POSIX. Ils ont dû choisir un comportement et il y a des inconvénients à aller à l'encontre des attentes des utilisateurs.Je pense que c'est l'aspect le moins influent historiquement de la question, donc je l'ai gardé pour la fin ... mais il convient de mentionner qu'il y a quelque chose de conceptuellement étrange dans le
nullglob
comportement.nullglob
semble élégant au premier abord parce que, syntaxiquement , il ne traite pas le cas des fichiers correspondant à zéro différemment du cas d'un, deux ou tout autre numéro. Les commandes que nous exécutons, pour lesquelles les globs se développent en arguments, n'ont pas tendance à les traiter de la même manière, comme détaillé ci-dessus. Mais syntaxiquement, cela semble au moins juste, ce qui, à mon avis, est la motivation de votre question.Et pourtant, il y a une autre incohérence plus subtile qui
nullglob
ne résout pas - qu'elle amplifie en fait. Le cas des caractères de globulation zéro ("caractères génériques") est traité différemment de celui d'un, de deux ou de tout autre nombre. Par exemple, avecshopt -s nullglob
, siab?d?f
ne correspond à aucun fichier, il est supprimé; s'ilab?d
ne correspond à aucun fichier, il est supprimé; mais s'ilab
ne correspond à aucun fichier (c'est-à-dire s'il n'y a pas de fichier dont le nom est exactementab
), il n'est toujours pas supprimé. Bien sûr, ce serait un désastre s'il était supprimé, car il pourrait ne pas être destiné du tout à faire référence à un fichier existant dans le répertoire courant; il pourrait même ne pas faire référence à un fichier. Mais cela élimine toujours tout espoir de cohérence totale.Les trois comportements fournis par bash - la valeur par défaut de traiter les globes qui ne correspondent à aucun fichier comme s'ils n'étaient pas des globes et de les transmettre non expansés, le comportement que vous attendiez de les traiter (si vous pardonnez cette étrange tournure de phrase) comme signifiant tout le zéro des fichiers qui correspondent (
nullglob
), et le comportement sûr de les considérer comme des erreurs (failglob
) - tous représentent des approches différentes de l'ambiguïté inhérente au shell ne pouvant pas savoir si un mot particulier est destiné à être un nom de fichier. Le shell effectue ses extensions sans savoir comment les commandes particulières que vous appelez avec lui traiteront 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 pièce est destinée à faire une chose et à bien la faire . Le shell traite le texte en commandes et arguments et appelle ces commandes, dont la plupart 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 l'exécution de ces transformations (comme avec les processeurs de commandes traditionnels sous DOS et Windows). Mais il a ses inconvénients occasionnels.
la source
failglob
. Il ne peut donc pas être par défaut car il n'a pas toujours été pris en charge.La raison principale est que c'est un comportement standard spécifié par POSIX - la norme qui couvre le langage de commande du shell et entre autres la correspondance de modèles (shells tels que
bash
,dash
shell - la valeur par défaut d'Ubuntu/bin/sh
, etksh
suivez cette norme). De la section 2.13.3 Modèles utilisés pour l'extension du nom de fichier :Bien sûr, cela a un effet secondaire - le nom de fichier correspondant peut être littéralement
*.txt
. L'nullglob
option dansbash
etzsh
peut aider: si cette option est activée viashopt -s nullglob
(et si elle n'est pas activée par défaut qui s'applique à cette question), globstar sera étendu à une chaîne vide lorsqu'aucun nom de fichier correspondant ne sera trouvé.ksh93
a son propre mécanisme avancé de mise en correspondance de motifs qui produit le même effet~(N)*.txt
Voir aussi Pourquoi nullglob n'est-il pas par défaut?
la source