Comportement inattendu avec l'écho [[: digit:]]

10

Je voudrais demander:

Pourquoi est echo {1,2,3}étendu à 1 2 3, ce qui est un comportement attendu, tandis que echo [[:digit:]]revient [[:digit:]]alors que je m'attendais à ce qu'il imprime tous les chiffres de 0à 9?

AbdAllah Talaat
la source
Attention: unix.stackexchange.com/q/347950/117549
Jeff Schaller

Réponses:

34

Parce que ce sont deux choses différentes. Le {1,2,3}est un exemple d' expansion du corset . La {1,2,3}construction est développée par le shell , avant echomême de la voir. Vous pouvez voir ce qui se passe si vous utilisez set -x:

$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3

Comme vous pouvez le voir, la commande echo {1,2,3}est étendue à:

echo 1 2 3

Cependant, [[:digit:]]est une classe de caractères POSIX . Lorsque vous le donnez echo, le shell le traite également en premier, mais cette fois, il est traité comme un glob de shell . cela fonctionne de la même manière que si vous exécutez echo *qui imprimera tous les fichiers du répertoire courant. Mais [[:digit:]]c'est un glob de shell qui correspondra à n'importe quel chiffre. Maintenant, en bash, si un glob de shell ne correspond à rien, il sera étendu à lui-même:

$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files

Si le glob correspond à quelque chose, cela sera imprimé:

$ echo /e*c
+ echo /etc
/etc

Dans les deux cas, echoimprime simplement ce que le shell lui dit d'imprimer, mais dans le second cas, puisque le glob correspond à quelque chose ( /etc), il est dit d'imprimer ce quelque chose.

Donc, comme vous n'avez pas de fichiers ou de répertoires dont le nom se compose exactement d'un chiffre (ce [[:digit:]]qui correspondrait), le glob est étendu à lui-même et vous obtenez:

$ echo [[:digit:]]
[[:digit:]]

Maintenant, essayez de créer un fichier appelé 5et d'exécuter la même commande:

$ echo [[:digit:]]
5

Et s'il y a plus d'un fichier correspondant:

$ touch 1 5       
$ echo [[:digit:]]
1 5

Ceci est (en quelque sorte) documenté dans man bashl'explication des nullgloboptions qui désactive ce comportement:

nullglob
    If  set,  bash allows patterns which match no files (see
    Pathname Expansion above) to expand to  a  null  string,
    rather than themselves.

Si vous définissez cette option:

$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]]  ## prints nothing

$ 
terdon
la source
4
Voir aussi shopt -s failglobpour obtenir un comportement plus utile similaire à celui des coques modernes comme zshou fish.
Stéphane Chazelas
Je suis d'accord avec Stéphane, utilise failglob. nullglobpeut provoquer des problèmes inattendus, par exemple lors du collage d'une URL qui se trouve avoir un ?.
Kevin
1
Bien sûr, je n'ai mentionné que nullglobpour démontrer que le motif est interprété comme un glob par le shell.
terdon
14

{1,2,3}est l' expansion de l'accolade , elle s'étend aux mots énumérés sans égard à leur signification.

[...]est un groupe de caractères, utilisé dans l' expansion du nom de fichier (ou caractère générique ou glob) de manière similaire à l'astérisque *et au point d'interrogation ?. Il correspond à tout caractère unique figurant dans la liste ou aux caractères qui sont membres de groupes nommés, comme [:digit:]si ceux-ci sont répertoriés. Le comportement par défaut de la plupart des shells consiste à laisser le caractère générique tel quel s'il n'y a aucun fichier qui le corresponde.

(Notez que vous ne pouvez pas vraiment transformer un caractère générique / motif en l'ensemble de chaînes qu'il correspondrait. L'astérisque peut correspondre à n'importe quelle chaîne de n'importe quelle longueur, donc étendre n'importe quel modèle le contenant produirait une liste infinie de chaînes.)

Donc:

$ bash -c 'echo [[:digit:]]'           # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]'            # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]'           # now there are two matches
1 3                                    # note that d, i, g and t do NOT match

Mais reste:

$ bash -c 'echo {1,2,3}'
1 2 3

Les deux sont développés par le shell , peu importe si la commande que vous exécutez est ls, ou echoou rm. Notez également que si l'un d'eux est cité, ils ne seront pas développés:

$ bash -c 'echo "[[:digit:]]"'         # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}
ilkkachu
la source
merci pour votre réponse, je suis nouveau sur linux alors permettez-moi de vous demander comment l'écho est lié aux fichiers 1 3, sa fonction est d'imprimer ses arguments à stdout ne recherchant pas de fichiers à ma connaissance
AbdAllah Talaat
1
@AbdAllahTalaat cela n'a rien à voir avec l'écho, en fait. Le shell (par exemple bash) "se développera" [[:digit:]] avant de le passer à echo, donc echone voit jamais [[:digit:]], il ne voit que 1 3. Vous pouvez le voir en action en exécutant set -xce qui affichera les commandes en cours d'exécution (exécutez-le set +xpour le désactiver à nouveau).
terdon
@AbdAllahTalaat, echone recherche pas de fichiers, le shell le fait, avant d'exécuter le echo.
ilkkachu
Surtout que je pense que sous DOS / Windows, les utilitaires développent les caractères génériques, pas le shell. (Je me trompe peut-être)
ilkkachu
désolé les gars j'ai changé la bonne réponse à la réponse de tedron parce que son commentaire contenait le sens que bash est ce que le travail ne fait pas écho ... sa réponse aussi contenait ce sens .. vous m'avez tous aidé ... je souhaitais si je pouvais mettre bonne réponse pour toutes vos réponses et commentaires
AbdAllah Talaat
4

{1,2,3}(et par exemple {1..3}sont des extensions d'accolade . Elles sont interprétées par le shell avant l'exécution de la commande.

[[:digit:]]est un jeton de correspondance de modèle , mais vous ne l'utilisez pas dans un emplacement contenant des fichiers correspondant à ce modèle. Si vous utilisez une correspondance de modèle qui n'a aucune correspondance, elle se développe à elle-même:

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3
DopeGhoti
la source
Non, comme les autres réponses l'indiquent correctement, le modèle est comparé aux noms de fichiers.
Toby Speight