Dans tous les shells dont je suis au courant, rm [A-Z]*
supprime tous les fichiers commençant par une lettre majuscule, mais avec bash, tous les fichiers commençant par une lettre sont supprimés.
Comme ce problème existe sous Linux et Solaris avec bash-3 et bash-4, il ne peut pas s'agir d'un bogue causé par un matcher de motif de buggy dans libc ou par une définition de paramètres régionaux mal configurée.
Ce comportement étrange et risqué est-il prévu ou s'agit-il simplement d'un bug qui existe depuis plusieurs années?
locale
sortie? Je ne peux pas reproduire ceci (touch foo; echo [A-Z]*
sort le motif littéral, pas "foo", dans un répertoire autrement vide).# echo [A-Z]* ; export LC_COLLATE=C ; echo [A-Z]*
A b B z ZABZRéponses:
LC_COLLATE
est une variable qui détermine l'ordre de classement utilisé lors du tri des résultats de l'expansion du chemin, et détermine le comportement des expressions de plage, des classes d'équivalence et des séquences de classement lors du développement du chemin et de la correspondance de motifs.Considérer ce qui suit:
Notez que lorsque la commande
echo [a-z]
est appelée, la sortie attendue serait tous les fichiers avec des caractères minuscules. En outre, avececho [A-Z]
, les fichiers avec des caractères majuscules sont attendus.Les classements standard avec des paramètres régionaux, tels que
en_US
l'ordre suivant:a
etz
(en[a-z]
) sont TOUTES les lettres majuscules, sauf pourZ
.A
etZ
(en[A-Z]
) sont TOUTES les lettres minuscules, à l'exception dea
.Voir:
Si vous modifiez la
LC_COLLATE
variable pourC
qu'elle ressemble comme prévu:Donc, ce n'est pas un bug , c'est un problème de classement .
Au lieu des expressions de plage, vous pouvez utiliser les classes de caractères définies par POSIX , telles que
upper
oulower
. Ils fonctionnent aussi avec différentesLC_COLLATE
configurations et même avec des caractères accentués :la source
tr
c’est ce que j’ai vérifié en premier.LC_COLLATE
ce qui est également documenté dans le manuel.[A-Z]
inbash
correspond à tous les éléments de classement (les caractères mais appellent également une séquence de caractères commeDsz
dans les paramètres régionaux hongrois) qui trient aprèsA
et trient avantZ
. Dans votre région, lesc
tris probablement entre B et C.Donc
c
ouz
serait assorti par[A-Z]
, mais pasẐ
oua
.Dans les paramètres régionaux C, l'ordre serait:
Alors
[A-Z]
correspondraitA
,B
,C
,Z
, mais pasÇ
et toujours pasẐ
.Si vous voulez faire correspondre les lettres majuscules (dans n'importe quel script), vous pouvez utiliser à la
[[:upper:]]
place. Il n'y a pas de moyen intégré debash
faire correspondre uniquement les lettres majuscules dans le script latin (sauf en les listant individuellement).Si vous voulez faire correspondre l'
A
àZ
anglais lettres sans signes diacritiques, vous pouvez utiliser[A-Z]
ou[[:upper:]]
mais dans leC
lieu ( en supposant que les données ne sont pas codées dans les jeux de caractères comme GRAND5 ou GB18030 qui a plusieurs caractères dont le codage contient l'encodage de ces lettres) ou de la liste individuellement ([ABCDEFGHIJKLMNOPQRSTUVWXYZ]
).Notez qu'il existe certaines variations entre les coquilles.
For
zsh
,bash -O globasciiranges
(option étrangement nommée introduite dans bash-4.3),schily-sh
etyash
, les[A-Z]
correspondances sur les caractères dont le point de code est compris entre celui deA
et celui deZ
, seraient donc équivalentes au comportement debash
la locale C.Pour les cendres, les mksh et les coquilles anciennes, comme
zsh
ci-dessus, mais limité aux jeux de caractères codés sur un octet. C’est-à-dire que, dans un environnement local UTF-8 par exemple,[É-Ź]
ne correspondrait pas àÓ
, mais puisque cela[<c3><89>-<c5><b9>]
correspond aux valeurs d’octets 0x89 à 0xc5!ksh93
se comporte commebash
si ce n’était les cas spéciaux dont les extrémités commençaient par des lettres minuscules ou des lettres majuscules. Dans ce cas, seuls les éléments de classement triés entre ces extrémités sont appariés, mais qui sont (ou leur premier caractère pour les éléments de classement multi-caractères) également en minuscule (ou majuscule, respectivement). Donc,[A-Z]
il y aurait correspondanceÉ
, mais pase
commee
trie entreA
etZ
mais n'est pas comme majusculeA
etZ
.Pour les
fnmatch()
modèles (comme dansfind -name '[A-Z]'
) ou les expressions régulières système (comme dansgrep '[A-Z]'
), cela dépend du système et des paramètres régionaux. Par exemple, sur un système GNU ici,[A-Z]
ne correspond pasx
à l'en_GB.UTF-8
environnement local, mais au contraireth_TH.UTF-8
. Les informations utilisées pour déterminer cela ne sont pas claires, mais elles sont apparemment basées sur une table de consultation dérivée des données de paramètres régionaux LC_COLLATE ).POSIX autorise tous les comportements, car POSIX laisse le comportement des plages non spécifiées dans des paramètres régionaux autres que les paramètres régionaux C. Nous pouvons maintenant discuter des avantages de chaque approche.
bash
Cette approche a beaucoup de sens car[C-G]
nous voulons que les personnages se situent entreC
etG
. Et l'utilisation de l'ordre de tri de l'utilisateur pour déterminer ce qui est intermédiaire est l'approche la plus logique.Le problème, c’est que cela répond aux attentes de beaucoup de gens, en particulier de ceux qui sont habitués au comportement traditionnel du pré-Unicode, même des jours qui précédaient l’internationalisation. Bien que d'un utilisateur normal, il est logique mai qui
[C-I]
comprendh
que lah
lettre est entreC
etI
et[A-g]
ne comprend pasZ
, il est une autre affaire pour les personnes ayant traité avec ASCII seulement pendant des décennies.Ce
bash
comportement est également différent de la[A-Z]
correspondance de plage dans d'autres outils GNU, comme dans les expressions régulières GNU (comme dansgrep
/sed
...) oufnmatch()
comme dansfind -name
.Cela signifie également que ce qui
[A-Z]
correspond à l'environnement, au système d'exploitation et à la version du système d'exploitation. Le fait de[A-Z]
correspondre à Á mais pas à Ź est également sous-optimal.Pour
zsh
/yash
, nous utilisons un ordre de tri différent. Au lieu de s’appuyer sur la notion d’ordre des caractères de l’utilisateur, nous utilisons les valeurs de code des points de caractère. Cela a l'avantage d'être facile à comprendre, mais d'un point de vue pratique, en dehors de l'ASCII, ce n'est pas très utile.[A-Z]
correspond aux 26 lettres majuscules anglais anglais,[0-9]
correspond aux chiffres décimaux. Il existe des points de code dans Unicode qui suivent l'ordre de certains alphabets mais ce n'est pas généralisé et ne peut pas être généralisé car de toute façon, différentes personnes utilisant un même script ne sont pas nécessairement d'accord sur l'ordre des lettres.Pour les shells traditionnels et mksh, dash, c'est brisé (maintenant que la plupart des gens utilisent des caractères multi-octets), mais principalement parce qu'ils ne disposent pas encore d'une prise en charge multi-octets. Ajout d'un support multi-octets à coquilles comme
bash
etzsh
a été un énorme effort et est toujours en cours.yash
(un shell japonais) a été initialement conçu avec une prise en charge multi-octets.L'approche de ksh93 présente l'avantage d'être compatible avec les expressions régulières du système ou avec fnmatch () (ou du moins, du moins sur les systèmes GNU). Là, cela ne brise pas l'attente de certaines personnes, car il
[A-Z]
n'inclut pas les lettres minuscules,[A-Z]
inclutÉ
(et Á, mais pas). Ce n'est pas compatible avecsort
ou généralement l'strcoll()
ordre.la source
mksh
(tous deux dérivés de pdksh).posh -c $'case Ó in [É-Ź]) echo yes; esac'
ne renvoie rien.sort
parce que lesbash
globs sont basés sur l'ordre de tri des caractères. Je n'ai actuellement pas accès à une version aussi ancienne debash
, mais je peux vérifier plus tard. Était-ce différent alors?\xFF
y a l' octet 0xFF, pas le caractère U + 00FF (ÿ
lui-même codé en tant que 0xC3 0xBF).\xFF
seul ne forme pas un caractère valide, je ne vois donc pas pourquoi il devrait être assorti[É-Ź]
.Il est prévu et documenté dans la
bash
documentation, section de correspondance de modèle . L'expression de plage[X-Y]
comprendra tous les caractères compris entreX
etY
utilisant la séquence et le jeu de caractères de la locale en cours:Vous pouvez voir,
b
triés entreA
etZ
dans lesen_US.utf8
paramètres régionaux.Vous avez plusieurs choix pour empêcher ce problème:
ou activer
globasciiranges
(à partir de 4.3 et plus):la source
J'ai observé ce comportement sur une nouvelle instance Amazon EC2. Puisque le PO n’a pas offert de MCVE , je vais en poster un:
Donc, ne pas avoir mon
LC_*
jeu entraîne la sortie de bash 4.1.2 (1) sur Linux pour produire un comportement apparemment étrange. Je peux basculer de manière fiable le comportement étrange en définissant et en désactivant les variables de paramètres régionaux respectives. Sans surprise, ce comportement semble être cohérent lors de l'exportation:Bien que bash se comporte comme si Stéphane "Shellshock" répondait Chazelas , je pense que la documentation de bash sur la correspondance des modèles est un buggy:
J'ai lu cette phrase (l'emphase mienne) comme suit: "si les variables de paramètres régionaux pertinentes ne sont pas définies, bash utilisera par défaut les paramètres régionaux C". Bash ne semble pas le faire. Au lieu de cela, il semble que les paramètres régionaux par défaut soient triés dans l'ordre du dictionnaire avec le repliement diacritique:
Je pense qu'il serait bon que bash documente comment il se comportera quand
LC_*
(spécifiquementLC_CTYPE
etLC_COLLATE
) ne sont pas définis. Mais dans le même temps, je partagerai un peu de sagesse :et
Mise à jour Sur la base du commentaire de @ G-Man, examinons ce qui se passe:
Ah ah! Cela explique le classement vu précédemment. Supprimons toutes les variables de locale:
Nous y voilà. Maintenant, bash fonctionne de manière cohérente en ce qui concerne la documentation sur ce système Linux. Si l' une des variables locale sont définies (
LANGUAGE
,LANG
,LC_COLLATE
,LC_CTYPE
,LC_ALL
, etc.) , puis Bash utilise celles selon son manuel. Sinon, bash retombe à C.La FAQ de Wooledge bash dit ceci:
Ainsi, le problème apparent, à la fois en termes de fonctionnement et de documentation, peut être expliqué en regardant la somme totale de toutes les variables de contrôle des paramètres régionaux.
la source
C
paramètres régionaux, il s'agit d'un bogue.env | grep LANG
ouecho "$LANG"
.LANG
. Avec cet indice, tout est expliqué.Les paramètres régionaux peuvent modifier les caractères correspondants
[A-Z]
. Utilisationéliminer l'influence. (J'ai utilisé un sous-shell pour localiser le changement).
la source
export LC_ALL=C
abord.Comme cela a déjà été dit, il s’agit d’un problème d’ordre de classement.
La plage az peut contenir des lettres majuscules dans certaines langues:
La solution correcte depuis bash 4.3 consiste à définir l’option suivante
globasciiranges
:faire que bash agisse comme si elle
LC_COLLATE=C
avait été définie dans des gammes globales .la source
Il semble que j'ai trouvé la bonne réponse à ma propre question:
Bash est un bug car il ne gère pas ses propres paramètres régionaux. Donc, définir LC_ * dans un processus bash est sans effet dans ce processus shell.
Si vous définissez LC_COLLATE = C, puis démarrez un autre bash, la suppression fonctionne comme prévu dans le nouveau processus bash.
la source
export
fait correctement.