Bash Globbing pas comme prévu

8

Ceci est une question de devoirs:

Faites correspondre tous les noms de fichiers avec 2 caractères ou plus qui commencent par une lettre minuscule, mais ne se terminent pas par une lettre majuscule.

Je ne comprends pas pourquoi ma solution ne fonctionne pas.

J'ai donc exécuté ce qui suit:

touch aa
touch ha
touch ah
touch hh
touch a123e
touch hX
touch Ax

ls [a-z]*[!A-Z]

Production:

aa  ha

Ma question: pourquoi ne correspond-elle pas à "ah", "hh" ou "a123e"?

Cœur sombre
la source
Fonctionne pour moi correctement sous mkshshell, mais pas bash --posix, donc il doit y avoir une règle spécifique pour bash`
Sergiy Kolodyazhnyy
@Serg, notez que le comportement de [AZ] n'est pas spécifié par POSIX, sauf dans les paramètres régionaux C. mkshcomme zshl » [A-Z]ne correspond pas Épar exemple. Les [A-Z]matchs de ksh93 sont activés Émais pas activés h.
Stéphane Chazelas

Réponses:

9

Il s'agit d'un problème de localisation . Dans votre environnement local, se [A-Z]développe en quelque chose comme [AbBcZ...zZ](plus probablement d'autres comme des caractères accentués), [^A-Z]signifie donc en fait "fichiers qui se terminent par a" dans votre exemple (et uniquement dans votre exemple).

Si vous voulez éviter une telle surprise, une façon consiste à définir LC_COLLATE=C car le classement est la partie de vos paramètres régionaux qui est responsable de l'ordre de tri. Aussi, vide LC_ALLs'il est défini, car il aurait la priorité.

$ ls [a-z]*[^A-Z]
aa  ha

$ ( LC_ALL=; LC_COLLATE=C; ls [a-z]*[^A-Z] )
a123e  aa  ah  ha  hh

Ou, mieux, il est probablement préférable de ne pas modifier vos paramètres régionaux et d'utiliser les classes appropriées: [:lower:]au lieu de [a-z]et [:upper:]au lieu de [A-Z].

$ ls [[:lower:]]*[^[:upper:]]
a123e  aa  ah  ha  hh

Ou utilisez l' globasciirangesoption de bash :

$ shopt -s globasciiranges
$ ls [a-z]*[^A-Z]
a123e  aa  ah  ha  hh

$ shopt -u globasciiranges
$ ls [a-z]*[^A-Z]
aa  ha
xhienne
la source
@heemayl, no LC_ALL=C ls [a-z]*[^A-Z]n'affecterait que les lsparamètres régionaux de, pas les paramètres régionaux utilisés par le shell pour développer le glob ou analyser cette ligne de commande.
Stéphane Chazelas
Vous n'avez pas besoin d'exporter LC_xxxpour qu'il s'applique au glob, mais il serait préférable que ls ait les mêmes paramètres régionaux.
Stéphane Chazelas
1
Notez que dans un environnement local où le jeu de caractères est GB18030 par exemple, avec l'approche LC_ALL = C, il ne pourrait pas correspondre sur un fichier appelé test-鏏par exemple, car une fois que vous changez le jeu de caractères en celui de l'environnement local C, devient <0xe7>A. IOW, lorsque vous modifiez LC_CTYPE, vous obtenez différents caractères.
Stéphane Chazelas
1
Notez que je soupçonne que [AZ] dans les paramètres régionaux de l'OP couvre plus que AbBcC ... zZ. Il a probablement aussi é, Á(mais probablement pas Ź). IOW, l'utilisation [A-Z]n'a pas de sens en dehors des paramètres régionaux C.
Stéphane Chazelas
@ StéphaneChazelas Merci pour vos excellents retours. Réponse mise à jour. Je crois que j'ai tout pris en compte.
xhienne