Esa es una consecuencia de que los personajes tienen el mismo orden de clasificación.
También notarás que
sort -u << EOF
■
⅕
⅖
⅗
EOF
devuelve solo una línea.
O eso:
expr ■ = ⅕
devuelve verdadero (como lo requiere POSIX).
La mayoría de las configuraciones regionales que se envían con sistemas GNU tienen varios caracteres (e incluso secuencias de caracteres (secuencias de clasificación)) que tienen el mismo orden de clasificación. En el caso de esos ■ ⅕⅖⅗, es porque el orden no está definido, y aquellos caracteres cuyo orden no está definido terminan teniendo el mismo orden de clasificación en los sistemas GNU. Hay caracteres que se definen explícitamente como que tienen el mismo orden de clasificación como Ș y Ş (aunque no hay una lógica real o coherencia aparente (para mí de todos modos) sobre cómo se hace).
Esa es la fuente de comportamientos bastante sorprendentes y falsos. Recientemente he planteado el tema en la lista de correo del grupo de Austin (el cuerpo detrás de POSIX y la Especificación Única de UNIX) y la discusión aún continúa a partir del 03/04/2015.
En este caso, no [y]
debería estar claro si debería coincidir con x
dónde x
y y
ordenar lo mismo, pero dado que una expresión de paréntesis debe coincidir con un elemento de clasificación, eso sugiere que bash
se espera el comportamiento.
En cualquier caso, supongo [⅕-⅕]
o al menos [⅕-⅖]
debería coincidir ■
.
Notarás que las diferentes herramientas se comportan de manera diferente. ksh93 se comporta como bash
GNU grep
o sed
no. Algunos otros depósitos tienen comportamientos diferentes, a algunos les gusta yash
aún más con errores.
Para tener un comportamiento consistente, necesita una configuración regional donde todos los caracteres se ordenan de manera diferente. La configuración regional C es la típica. Sin embargo, el conjunto de caracteres en la configuración regional C en la mayoría de los sistemas es ASCII. En los sistemas GNU, generalmente tiene acceso a un C.UTF-8
entorno local que se puede utilizar para trabajar en el carácter UTF-8.
Entonces:
(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])
o el equivalente estándar:
(export LC_ALL=C.UTF-8
case ■ in ([⅕⅖⅗]) true;; (*) false; esac)
debería devolver falso.
Otra alternativa sería establecer solo LC_COLLATE
en C, que funcionaría en los sistemas GNU, pero no necesariamente en otros en los que podría no especificarse el orden de clasificación del carácter de varios bytes.
Una lección de eso es que la igualdad no es una noción tan clara como cabría esperar cuando se trata de comparar cadenas. Igualdad podría significar, de lo más estricto a lo menos estricto.
- El mismo número de bytes y todos los constituyentes de bytes tienen el mismo valor.
- El mismo número de caracteres y todos los caracteres son iguales (por ejemplo, consulte el mismo punto de código en el juego de caracteres actual).
- Las dos cadenas tienen el mismo orden de clasificación que el algoritmo de clasificación del entorno local (es decir, ni a <b ni b> a es verdadero).
Ahora, para 2 o 3, se supone que ambas cadenas contienen caracteres válidos. En UTF-8 y algunas otras codificaciones, algunas secuencias de bytes no forman caracteres válidos.
1 y 2 no son necesariamente equivalentes por eso o porque algunos caracteres pueden tener más de una codificación posible. Ese suele ser el caso de codificaciones con estado como ISO-2022-JP, donde A
se pueden expresar como 41
o 1b 28 42 41
( 1b 28 42
siendo la secuencia para cambiar a ASCII y se pueden insertar tantas de las que desee, eso no hará la diferencia), aunque yo no esperaría que esos tipos de codificación aún estén en uso, y las herramientas GNU al menos generalmente no funcionan correctamente con ellas.
También tenga en cuenta que la mayoría de las utilidades que no son GNU no pueden manejar el valor de 0 bytes (el carácter NUL en ASCII).
Cuál de esas definiciones se usa depende de la utilidad y la implementación o versión de la utilidad. POSIX no es 100% claro en eso. En la configuración regional C, los 3 son equivalentes. Fuera de ese YMMV.