¿Por qué el asterisco [az] coincide con los números?

13

Tengo 3 directorios en la ruta actual.

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

Esperaba que el último comando ls coincidiera solo a_clean_data. ¿Por qué también coincidió con el que contiene 0?

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
usuario13107
fuente
2
Vea esta pregunta para obtener más información sobre la diferencia entre una expresión regular y un glob.
terdon
44
Entonces, ¿el hecho de que a_*_datacoincida con alguno de estos archivos no te sorprendió?
Cthulhu
@Cthulhu me tienes!
user13107

Respuestas:

29

La [a-z]parte no es lo que coincide con el número; es el *. Puede ser confuso el shell globbing y las expresiones regulares .

Herramientas como grepaceptar varios tipos de expresiones regulares ( básico de forma predeterminada, -Epara extendido, -Ppara expresiones regulares de Perl )

Por ejemplo ( -vinvierte el partido)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

Si desea utilizar una expresión regular de bash, aquí hay un ejemplo sobre cómo probar si la variable $refes un número entero:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi
Sebastian
fuente
¿Cómo usar bash regex entonces? (ver tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html )
user13107
1
ver esta pregunta
umläute
21

Entonces el problema es: ¿por qué a_[a-z]*_datacoincide a_clean_0db_data?

Esto se puede dividir en cuatro partes:

  • a_coincide con el comienzo de a_clean_0db_data, dejando clean_0db_dataque coincida

  • [a-z]coincide con cualquier personaje en el rango a-z(por ejemplo c), dejando lean_0db_dataque coincida

  • * coincide con cualquier número de caracteres, p. ej. lean_0db

  • _data coincide con el final _data

En las expresiones regulares, [a-z]*significaría cualquier número de caracteres (incluido cero) en el rango de a..z , pero se trata de un bloqueo de shell, no de expresiones regulares.

Si desea expresiones regulares, algunas findimplementaciones tienen un -regexpredicado para eso:

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

El -maxdepthes aquí sólo para limitar los resultados de búsqueda-a la carpeta que se encuentra. La expresión regular coincide con la totalidad de nombre de archivo, por lo tanto, he añadido una ^.*/para que coincida con la parte de ruta

umläute
fuente
11

*en los patrones de shell coincide con 0 o más caracteres. No debe confundirse con el *operador de expresión regular que significa 0 o más del átomo anterior .

No hay equivalente de regexp *en los patrones básicos de shell. Sin embargo, varios shells tienen extensiones para eso.

  • kshtiene *(something):

    ls a_*([a-z])_data
  • puede tener lo mismo bashcon shopt -s extglobo zshcon setopt kshglob:

    shopt -s extglob
    ls a_*([a-z])_data
  • En zshcon extendedglobhabilitado, #es equivalente a regexp *:

    setopt extendedglob
    ls a_[a-z]#_data
  • En versiones recientes de ksh93, también puede usar expresiones regulares en globos. Aquí con expresiones regulares extendidas :

    ls ~(E:a_[a-z]*_data)

Tenga en cuenta que [a-z]coincide con diferentes cosas según la configuración regional actual. Por lo general coincide con sólo las 26 aa zlas letras latinas no acentuados en la Cconfiguración regional. En otros entornos locales, generalmente coincide más y no siempre tiene sentido. Para que coincida con una letra en su localidad, puede preferir [[:alpha:]].

Stéphane Chazelas
fuente
¿Podría dar un ejemplo de [a-z]coincidencia más que las 26 letras coincidentes en la configuración regional C? Lo que recuerdo de la última vez que vi esto, todas las codificaciones prácticamente utilizadas en las variantes de Unix tenían ISO-646 como base (luego los 128 códigos superiores se usaron de manera diferente, directamente para caracteres en codificaciones como el ISO-8859-X, combinados en codificaciones como UTF-8 o la familia EUC). Incluso AIX no tenía configuraciones regionales EBCDIC (al menos como estaba disponible para mí). Recuerdo haber intentado averiguar si los estándares POSIX / UNIX lo exigían, pero no recuerdo el resultado.
Programador
1
@AProgrammer, que es independiente de la codificación, que se basa en el orden de clasificación (LC_COLLATE). [a-z]generalmente incluye éo í(pero no necesariamente ź) en los entornos locales donde el conjunto de caracteres los tiene, ya sea que el punto de código en esa codificación esté entre el de a y z o no. Solo la configuración regional C garantiza un orden de clasificación basado en el valor del punto de código. Vea esta otra respuesta para más detalles.
Stéphane Chazelas
Ok, lo que me perdí fue que el rango fue interpretado de acuerdo con la secuencia de clasificación actual.
Programador