Pourquoi l'astérisque [a-z] correspond-il aux numéros?

13

J'ai 3 répertoires dans le chemin actuel.

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

Je m'attendais à ce que la dernière commande ls ne corresponde qu'à a_clean_data . Pourquoi a-t-il également correspondu à celui contenant 0 ?

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
    
posée user13107 10.09.2014 - 10:26
la source

3 réponses

29

La partie [a-z] ne correspond pas au nombre; c'est le * . Vous risquez de confondre le shell en baladant et expressions régulières .

Des outils tels que grep acceptent différents types de regex ( basic par défaut, -E pour étendu, -P pour expression régulière Perl )

E.g. ( -v inverse la correspondance)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

Si vous souhaitez utiliser une expression rationnelle bash, voici un exemple sur la façon de tester si la variable $ref est un entier:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi
    
réponse donnée 10.09.2014 - 10:36
la source
19

Le problème est donc: pourquoi a_[a-z]*_data correspond à a_clean_0db_data ?

Il peut être divisé en quatre parties:

  • a_ correspond au début de a_clean_0db_data , en laissant clean_0db_data à égaler

  • [a-z] correspond à n’importe quel caractère de la plage a-z (par exemple c ), laissant ainsi lean_0db_data correspondant

  • * correspond à un nombre quelconque de caractères, par exemple. lean_0db

  • _data correspond au dernier _data

Dans les expressions rationnelles, [a-z]* signifierait un nombre quelconque de caractères (y compris zéro) dans la plage de a..z , mais vous avez affaire à un déplacement de shell, pas à des expressions régulières.

Si vous voulez des expressions régulières, quelques implémentations de find ont un prédicat -regex pour cela:

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

Le -maxdepth n’est là que pour limiter les résultats de la recherche au dossier dans lequel vous vous trouvez. L'expression expression régulière correspond au nom de fichier entier . Par conséquent, j'ai ajouté un ^.*/ correspondant à la portion de chemin

.     
réponse donnée 10.09.2014 - 10:41
la source
10

* dans les modèles de shell correspond à 0 ou plusieurs caractères. À ne pas confondre avec l'opérateur d'expression régulière * qui signifie 0 ou plus de l'atome précédent .

Il n'y a pas d'équivalent de l'expression rationnelle * dans les modèles de shell de base. Cependant, plusieurs coques ont des extensions pour cela.

  • ksh a *(something) :

    ls a_*([a-z])_data
    
  • vous pouvez avoir la même chose dans bash avec shopt -s extglob ou zsh avec setopt kshglob :

    shopt -s extglob
    ls a_*([a-z])_data
    
  • Dans zsh avec extendedglob activé, # est équivalent à l'expression rationnelle * :

    setopt extendedglob
    ls a_[a-z]#_data
    
  • Dans les versions récentes de ksh93 , vous pouvez également utiliser des expressions régulières dans les globs. Ici, avec les expressions régulières étendues :

    ls ~(E:a_[a-z]*_data)
    

Notez que [a-z] correspond à différentes choses selon les paramètres régionaux en cours. En règle générale, il ne fait correspondre que les 26 a aux z lettres latines non accentuées de la région C . Dans d'autres régions, cela correspond généralement plus et n'a pas toujours de sens. Pour faire correspondre une lettre dans vos paramètres régionaux, vous préférerez peut-être [[:alpha:]] .

    
réponse donnée 10.09.2014 - 11:16
la source

Lire d'autres questions sur les étiquettes