C'est une conséquence du fait que ces caractères ont le même ordre de tri.
Vous remarquerez également que
sort -u << EOF
■
⅕
⅖
⅗
EOF
renvoie une seule ligne.
Ou ça:
expr ■ = ⅕
renvoie vrai (comme requis par POSIX).
La plupart des paramètres régionaux fournis avec les systèmes GNU ont un certain nombre de caractères (et même des séquences de caractères (séquences d'assemblage)) qui ont le même ordre de tri. Dans le cas de ces ■ ⅕⅖⅗, c'est parce que l'ordre n'est pas défini, et les caractères dont l'ordre n'est pas défini finissent par avoir le même ordre de tri dans les systèmes GNU. Il y a des caractères qui sont explicitement définis comme ayant le même ordre de tri comme Ș et Ş (bien qu'il n'y ait aucune logique ou cohérence réelle apparente (pour moi de toute façon) sur la façon dont cela est fait).
C'est la source de comportements assez surprenants et faux. J'ai soulevé la question très récemment sur la liste de diffusion du groupe Austin (le corps derrière POSIX et la spécification UNIX unique) et la discussion est toujours en cours depuis le 2015-04-03.
Dans ce cas, il [y]
ne faut pas savoir si doit correspondre x
où x
et y
trier la même chose, mais comme une expression entre crochets est censée correspondre à un élément de classement, cela suggère que le bash
comportement est attendu.
En tout cas, je suppose [⅕-⅕]
ou du moins [⅕-⅖]
devrait correspondre ■
.
Vous remarquerez que différents outils se comportent différemment. ksh93 se comporte comme bash
, GNU grep
ou sed
pas. Certains autres obus ont des comportements différents, certains comme yash
encore plus de buggy.
Pour avoir un comportement cohérent, vous avez besoin d'un environnement local où tous les caractères sont triés différemment. La locale C est la locale typique. Cependant, le jeu de caractères dans les paramètres régionaux C sur la plupart des systèmes est ASCII. Sur les systèmes GNU, vous avez généralement accès à un C.UTF-8
environnement local qui peut être utilisé à la place pour travailler sur le caractère UTF-8.
Donc:
(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])
ou l'équivalent standard:
(export LC_ALL=C.UTF-8
case ■ in ([⅕⅖⅗]) true;; (*) false; esac)
devrait retourner faux.
Une autre alternative serait de ne définir que LC_COLLATE
C qui fonctionnerait sur les systèmes GNU, mais pas nécessairement sur d'autres où il pourrait ne pas spécifier l'ordre de tri des caractères multi-octets.
L'une des leçons de cela est que l' égalité n'est pas une notion aussi claire qu'on pourrait s'y attendre lorsqu'il s'agit de comparer des chaînes. L'égalité peut signifier, du plus strict au moins strict.
- Le même nombre d'octets et tous les constituants d'octet ont la même valeur.
- Le même nombre de caractères et tous les caractères sont identiques (par exemple, faites référence au même point de code dans le jeu de caractères actuel).
- Les deux chaînes ont le même ordre de tri selon l'algorithme de classement des paramètres régionaux (c'est-à-dire que ni a <b ni b> a n'est vrai).
Maintenant, pour 2 ou 3, cela suppose que les deux chaînes contiennent des caractères valides. En UTF-8 et certains autres encodages, certaines séquences d'octets ne forment pas de caractères valides.
1 et 2 ne sont pas nécessairement équivalents à cause de cela, ou parce que certains caractères peuvent avoir plus d'un codage possible. C'est généralement le cas des codages avec état comme ISO-2022-JP où A
peut être exprimé comme 41
ou 1b 28 42 41
( 1b 28 42
étant la séquence pour passer en ASCII et vous pouvez en insérer autant que vous le souhaitez, cela ne fera aucune différence), bien que je ne s'attendrait pas à ce que ces types d'encodage soient toujours utilisés, et les outils GNU au moins ne fonctionnent généralement pas correctement avec eux.
Sachez également que la plupart des utilitaires non GNU ne peuvent pas gérer la valeur 0 octet (le caractère NUL en ASCII).
Laquelle de ces définitions est utilisée dépend de l'utilitaire et de sa mise en œuvre ou de sa version. POSIX n'est pas sûr à 100%. Dans les paramètres régionaux C, les 3 sont équivalents. En dehors de ce YMMV.