En todos los shells que conozco, rm [A-Z]*
elimina todos los archivos que comienzan con una letra mayúscula, pero con bash esto elimina todos los archivos que comienzan con una letra.
Como este problema existe en Linux y Solaris con bash-3 y bash-4, no puede ser un error causado por un emparejador de patrones con errores en libc o una definición de configuración regional mal configurada.
¿Se pretende este comportamiento extraño y arriesgado o es solo un error que existe sin reparar desde hace muchos años?
locale
salida? No puedo reproducir esto (touch foo; echo [A-Z]*
genera el patrón literal, no "foo", en un directorio vacío).# echo [A-Z]* ; export LC_COLLATE=C ; echo [A-Z]*
A b B z ZABZRespuestas:
LC_COLLATE
es una variable que determina el orden de clasificación utilizado al ordenar los resultados de la expansión del nombre de ruta y determina el comportamiento de las expresiones de rango, las clases de equivalencia y las secuencias de clasificación dentro de la expansión del nombre de ruta y la coincidencia de patrones.Considera lo siguiente:
Observe que cuando
echo [a-z]
se llama al comando , el resultado esperado sería todos los archivos con caracteres en minúscula. Además, conecho [A-Z]
, se esperarían archivos con caracteres en mayúscula.Las intercalaciones estándar con configuraciones regionales como las que
en_US
tienen el siguiente orden:a
yz
(in[a-z]
) están TODAS las letras mayúsculas, exceptoZ
.A
yZ
(in[A-Z]
) están TODAS las letras minúsculas, exceptoa
.Ver:
Si cambia la
LC_COLLATE
variable a la queC
se ve como se esperaba:Entonces, no es un error , es un problema de cotejo .
En lugar de expresiones de rango, puede usar clases de caracteres definidas POSIX , como
upper
olower
. Funcionan también con diferentesLC_COLLATE
configuraciones e incluso con caracteres acentuados :fuente
tr
esto es lo que verifiqué primero.LC_COLLATE
cual también se documenta en el manual.[A-Z]
enbash
coincide con todos los elementos de clasificación (los caracteres, pero la llamada también es una secuencia de caracteres comoDsz
en las configuraciones regionales húngaras) que se ordenan despuésA
y antesZ
. En su localidad,c
probablemente clasifique entre B y C.Entonces,
c
oz
sería igualado por[A-Z]
, pero noẐ
oa
.En la configuración regional C, el orden sería:
Así
[A-Z]
se corresponderíaA
,B
,C
,Z
, pero noÇ
y aún así noẐ
.Si desea hacer coincidir las letras mayúsculas (en cualquier secuencia de comandos), puede usar
[[:upper:]]
en su lugar. No hay una manera integrada debash
hacer coincidir solo las letras mayúsculas en el alfabeto latino (excepto al enumerarlas individualmente).Si desea que coincida con el
A
deZ
Inglés letras sin signos diacríticos, puede utilizar cualquiera[A-Z]
o[[:upper:]]
sino en laC
configuración regional (suponiendo que los datos no están codificados en los juegos de caracteres como Big5 o GB18030 que tiene varios personajes cuya codificación contiene la codificación de esas cartas) o lista ellos individualmente ([ABCDEFGHIJKLMNOPQRSTUVWXYZ]
).Tenga en cuenta que hay alguna variación entre los depósitos.
For
zsh
,bash -O globasciiranges
(opción extrañamente nombrada introducida en bash-4.3),schily-sh
yyash
,[A-Z]
coincide con los caracteres cuyo punto de código está entre el deA
y el deZ
, por lo que sería equivalente al comportamiento debash
en la configuración regional de C.Para cenizas, mksh y conchas antiguas, igual que el
zsh
anterior pero limitado a conjuntos de caracteres de un solo byte. Es decir, en un entorno local UTF-8, por ejemplo,[É-Ź]
no coincidiríaÓ
, pero como eso[<c3><89>-<c5><b9>]
, ¡coincidiría con los valores de bytes 0x89 a 0xc5!ksh93
se comporta como,bash
excepto que trata como rangos de casos especiales cuyos extremos comienzan con letras minúsculas o mayúsculas. En ese caso, solo coincide en elementos de clasificación que se clasifican entre esos extremos, pero que son (o su primer carácter para elementos de clasificación de varios caracteres) también minúsculas (o mayúsculas respectivamente). Por[A-Z]
lo tanto , coincidiría conÉ
, pero no cone
loe
que se clasifica entreA
yZ
pero no es mayúscula comoA
yZ
.Para
fnmatch()
patrones (como enfind -name '[A-Z]'
) o expresiones regulares del sistema (como engrep '[A-Z]'
), depende del sistema y la configuración regional. Por ejemplo, en un sistema GNU aquí,[A-Z]
no coincidex
en laen_GB.UTF-8
configuración regional, pero sí en lath_TH.UTF-8
. No me queda claro qué información utiliza para determinar eso, pero aparentemente se basa en una tabla de búsqueda derivada de los datos de la configuración regional LC_COLLATE ).POSIX permite todos los comportamientos, ya que POSIX deja el comportamiento de los rangos sin especificar en configuraciones regionales distintas de la configuración regional C. Ahora podemos discutir sobre los beneficios de cada enfoque.
bash
El enfoque tiene mucho sentido ya que con[C-G]
, queremos los caracteres entreC
yG
. Y usar el orden de clasificación del usuario para determinar qué es lo intermedio es el enfoque más lógico.Ahora, el problema es que rompe las expectativas de muchas personas, especialmente aquellas personas acostumbradas al comportamiento tradicional de pre-Unicode, incluso los días previos a la internacionalización. Si bien desde un usuario normal, que tiene sentido de mayo que
[C-I]
incluyeh
como lah
carta es entreC
yI
y que[A-g]
no incluyeZ
, es un asunto diferente para las personas de haber tratado con ASCII solamente durante décadas.Ese
bash
comportamiento también es diferente de la[A-Z]
coincidencia de rango en otras herramientas de GNU como en las expresiones regulares de GNU (como engrep
/sed
...) ofnmatch()
como enfind -name
.También significa que lo que
[A-Z]
coincide varía con el entorno, con el sistema operativo y con la versión del sistema operativo. El hecho de que[A-Z]
coincida con Á pero no con Ź también es subóptimo.Para
zsh
/yash
, utilizamos un orden de clasificación diferente. En lugar de confiar en la noción de orden de caracteres del usuario, utilizamos los valores del código de punto de carácter. Tiene el beneficio de ser fácil de entender, pero desde un punto práctico de pocos, fuera de ASCII, no es muy útil.[A-Z]
coincide con las 26 letras mayúsculas del inglés de EE. UU.,[0-9]
coincide con los dígitos decimales. Hay puntos de código en Unicode que siguen el orden de algunos alfabetos, pero eso no está generalizado y no puede generalizarse, ya que de todos modos las diferentes personas que usan un mismo script no necesariamente están de acuerdo con el orden de las letras.Para los shells y mksh tradicionales, el guión está roto (ahora que la mayoría de las personas usa caracteres de varios bytes), pero principalmente porque todavía no tienen soporte para varios bytes. Agregar soporte de varios bytes a shells como
bash
yzsh
ha sido un gran esfuerzo y aún está en curso.yash
(un shell japonés) se diseñó inicialmente con soporte de múltiples bytes desde el principio.El enfoque de ksh93 tiene el beneficio de ser coherente con las expresiones regulares del sistema o fnmatch () (o al menos parece al menos en los sistemas GNU). Allí, no rompe las expectativas de algunas personas, ya
[A-Z]
que no incluye letras minúsculas,[A-Z]
incluyeÉ
(y Á, pero no Ź). No es consistente con el orden ensort
generalstrcoll()
.fuente
mksh
(ambos derivados de pdksh).posh -c $'case Ó in [É-Ź]) echo yes; esac'
no devuelve nadasort
porque losbash
globos se basan en el orden de clasificación de caracteres. Actualmente no tengo acceso a una versión tan antigua debash
, pero puedo verificar más tarde. ¿Fue diferente entonces?\xFF
existe el byte 0xFF, no el carácter U + 00FF (enÿ
sí mismo codificado como 0xC3 0xBF).\xFF
solo no forma un carácter válido, así que no puedo ver por qué debería coincidir con él[É-Ź]
.Está destinado y documentado en la
bash
documentación, sección de coincidencia de patrones . La expresión de rango[X-Y]
incluirá cualquier carácter entreX
yY
usando la secuencia de clasificación y el conjunto de caracteres de la configuración regional actual:Puede ver,
b
ordenado entreA
yZ
en laen_US.utf8
configuración regional.Tiene algunas opciones para evitar este comportamiento:
o habilitar
globasciiranges
(con bash 4.3 y superior):fuente
Observé este comportamiento en una nueva instancia de Amazon EC2. Como el OP no ofreció un MCVE , publicaré uno:
Entonces, no tener mi
LC_*
set leads bash 4.1.2 (1) -lanzamiento en Linux para producir un comportamiento aparentemente extraño. Puedo alternar de manera confiable el comportamiento extraño configurando y desarmando las variables locales respectivas. Como era de esperar, este comportamiento parece consistente a través de la exportación:Mientras veo que bash se comporta como Stéphane "Shellshock" Chazelas respondió , creo que la documentación de bash sobre la coincidencia de patrones tiene errores:
Leí esa oración (el énfasis es mío) como "si las variables locales relevantes no están establecidas, entonces bash pasará a la configuración regional C". Bash no parece estar haciendo eso. En cambio, parece estar predeterminado en un entorno local donde los caracteres se ordenan en orden de diccionario con plegado diacrítico:
Creo que sería bueno para bash documentar cómo se comportará cuando
LC_*
(específicamenteLC_CTYPE
yLC_COLLATE
) no estén definidos. Pero mientras tanto, compartiré algo de sabiduría :y
Actualización Basado en el comentario de @ G-Man, echemos un vistazo más profundo a lo que está sucediendo:
Ah, ja! Eso explica la recopilación vista anteriormente. Eliminemos todas las variables locales:
Aquí vamos. Ahora bash opera de manera consistente con respecto a la documentación en este sistema Linux. Si ninguna de las variables de entorno local se fijan (
LANGUAGE
,LANG
,LC_COLLATE
,LC_CTYPE
,LC_ALL
, etc.) entonces Bash utiliza aquellos de acuerdo con su manual. De lo contrario, bash vuelve a caer a C.Las preguntas frecuentes de Wooledge bash tienen esto que decir:
Por lo tanto, el problema aparente, tanto en la operación como en la documentación, puede explicarse observando la suma total de todas las variables de manejo locales.
fuente
C
configuración regional, esto es un error.env | grep LANG
oecho "$LANG"
.LANG
. Con esa pista, todo está explicado.La configuración regional puede cambiar los caracteres que coinciden
[A-Z]
. Utilizarpara eliminar la influencia. (Usé una subshell para localizar el cambio).
fuente
export LC_ALL=C
primero.Como ya se ha dicho, este es un problema de "orden de clasificación".
El rango az puede contener letras mayúsculas en algunas configuraciones regionales:
La solución correcta desde bash 4.3 es establecer la opción
globasciiranges
:hacer que bash actúe como si
LC_COLLATE=C
se hubiera establecido en rangos globales .fuente
Parece que encontré la respuesta correcta a mi propia pregunta:
Bash tiene errores, ya que no gestiona su propia configuración regional. Por lo tanto, configurar LC_ * en un proceso bash no tiene efecto en ese proceso de shell.
Si configura LC_COLLATE = C y luego inicia otra bash, el globing funciona como se espera en el nuevo proceso de bash.
fuente
export
correctamente.