J'ai 3 répertoires sur 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 corresponde uniquement a_clean_data
. Pourquoi cela correspondait-il aussi à celui qui le contenait 0
?
bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
bash
regular-expression
wildcards
user13107
la source
la source
a_*_data
correspondre à l'un de ces fichiers ne vous a pas surpris?Réponses:
La
[a-z]
partie n'est pas celle qui correspond au nombre; c'est le*
. Vous pouvez confondre le globbing du shell et les expressions régulières .Des outils comme
grep
accepter différentes saveurs d'expressions rationnelles (de base par défaut,-E
pour étendu,-P
pour l' expression rationnelle Perl )Par exemple (
-v
inverse le match)Si vous souhaitez utiliser une expression rationnelle bash, voici un exemple sur la façon de tester si la variable
$ref
est un entier:la source
Le problème est donc: pourquoi
a_[a-z]*_data
correspond-ila_clean_0db_data
?Cela peut être divisé en quatre parties:
a_
correspond au début dea_clean_0db_data
, laissantclean_0db_data
à correspondre[a-z]
correspond à n'importe quel caractère de la plagea-z
(par exemplec
), laissantlean_0db_data
à correspondre*
correspond à n'importe quel nombre de caractères, par exemplelean_0db
_data
correspond à la fin_data
Dans les expressions régulières,
[a-z]*
cela signifierait n'importe quel nombre de caractères (y compris zéro) dans la plage de a..z , mais vous avez affaire à un globbing shell, pas à des expressions régulières.Si vous voulez des expressions régulières, quelques
find
implémentations ont un-regex
prédicat pour cela:Le
-maxdepth
n'est là que pour limiter les résultats de la recherche au dossier dans lequel vous vous trouvez. L' expression régulière correspond au nom de fichier entier , j'ai donc ajouté un^.*/
pour correspondre au chemin-portionla source
*
dans les modèles shell correspond à 0 ou plusieurs caractères. Il ne faut pas le 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 regexp
*
dans les modèles de shell de base. Cependant, divers shells ont des extensions pour cela.ksh
a*(something)
:vous pouvez avoir la même chose
bash
avecshopt -s extglob
ouzsh
avecsetopt kshglob
:Dans
zsh
avecextendedglob
activé,#
est équivalent à regexp*
:Dans les versions récentes de
ksh93
, vous pouvez également utiliser des expressions régulières dans les globes. Ici avec des expressions régulières étendues :Notez que cela
[a-z]
correspond à différentes choses selon les paramètres régionaux actuels. Il correspond en général que les 26a
àz
lettres non-latin accentués dans leC
paramètres régionaux. Dans d'autres pays, cela correspond généralement davantage et n'a pas toujours de sens. Pour faire correspondre une lettre dans votre région, vous pouvez préférer[[:alpha:]]
.la source
[a-z]
correspondance plus que les 26 lettres correspondent dans les paramètres régionaux C? Ce dont je me souviens de la dernière fois que j'ai regardé cela, tous les encodages pratiquement utilisés dans les variantes Unix avaient ISO-646 comme base (puis les 128 codes supérieurs étaient utilisés différemment, directement pour les caractères dans des encodages comme ISO-8859-X, combinés dans codages comme UTF-8 ou la famille EUC). Même AIX n'avait pas de paramètres régionaux EBCDIC (au moins aussi disponibles pour moi). Je me souviens avoir essayé de trouver si les normes POSIX / UNIX l'exigeaient, mais je ne me souviens pas du résultat.[a-z]
inclut généralementé
ouí
(mais pas nécessairementź
) dans les paramètres régionaux où le jeu de caractères les a, que le point de code dans cet encodage soit entre celui de a et z ou non. Seul l'environnement local C garantit un ordre de tri basé sur la valeur du point de code. Voir cette autre réponse pour plus de détails.