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?

localesalida? 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_COLLATEes 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_UStienen el siguiente orden:ayz(in[a-z]) están TODAS las letras mayúsculas, exceptoZ.AyZ(in[A-Z]) están TODAS las letras minúsculas, exceptoa.Ver:
Si cambia la
LC_COLLATEvariable a la queCse 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
upperolower. Funcionan también con diferentesLC_COLLATEconfiguraciones e incluso con caracteres acentuados :fuente
tresto es lo que verifiqué primero.LC_COLLATEcual también se documenta en el manual.[A-Z]enbashcoincide con todos los elementos de clasificación (los caracteres, pero la llamada también es una secuencia de caracteres comoDszen las configuraciones regionales húngaras) que se ordenan despuésAy antesZ. En su localidad,cprobablemente clasifique entre B y C.Entonces,
cozserí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 debashhacer coincidir solo las letras mayúsculas en el alfabeto latino (excepto al enumerarlas individualmente).Si desea que coincida con el
AdeZInglés letras sin signos diacríticos, puede utilizar cualquiera[A-Z]o[[:upper:]]sino en laCconfiguració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-shyyash,[A-Z]coincide con los caracteres cuyo punto de código está entre el deAy el deZ, por lo que sería equivalente al comportamiento debashen la configuración regional de C.Para cenizas, mksh y conchas antiguas, igual que el
zshanterior 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!ksh93se comporta como,bashexcepto 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 coneloeque se clasifica entreAyZpero no es mayúscula comoAyZ.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 coincidexen laen_GB.UTF-8configuració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.
bashEl enfoque tiene mucho sentido ya que con[C-G], queremos los caracteres entreCyG. 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]incluyehcomo lahcarta es entreCyIy que[A-g]no incluyeZ, es un asunto diferente para las personas de haber tratado con ASCII solamente durante décadas.Ese
bashcomportamiento 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
bashyzshha 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 ensortgeneralstrcoll().fuente
mksh(ambos derivados de pdksh).posh -c $'case Ó in [É-Ź]) echo yes; esac'no devuelve nadasortporque losbashglobos 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?\xFFexiste el byte 0xFF, no el carácter U + 00FF (enÿsí mismo codificado como 0xC3 0xBF).\xFFsolo 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
bashdocumentación, sección de coincidencia de patrones . La expresión de rango[X-Y]incluirá cualquier carácter entreXyYusando la secuencia de clasificación y el conjunto de caracteres de la configuración regional actual:Puede ver,
bordenado entreAyZen laen_US.utf8configuració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_CTYPEyLC_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
Cconfiguración regional, esto es un error.env | grep LANGoecho "$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=Cprimero.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=Cse 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
exportcorrectamente.