¿Hay alguna razón histórica por la que Bash "globbing" y las expresiones regulares no sean idénticas? Por ejemplo, creo que en Bash [1-2]*
coincide todo lo que comienza con un 1 o un 2 seguido de cualquier otra cosa, mientras que como expresión regular [1-2]*
solo coincidiría con una secuencia de 1s y 2s. Mis secuencias de comandos Bash y REGEX son bastante débiles y regularmente me encuentro con problemas asociados con estas diferencias, lo que me hizo sentir curiosidad por saber por qué son diferentes.
11
rm -- ^[^.].*\.txt$
lugar derm -- *.txt
?find . -regex ".*\.txt$" | xargs rm --
orename
para renombrar archivos (essed
para nombres de archivos), tenga cuidado con algunos sistemas que tienen una diferenterename
.^[^.].*\.txt$
fue tener en cuenta el hecho de ignorar los archivos de puntos. Tenga en cuenta que el-regex
es un extensiones de GNU, algunas conchas como ksh93 o zsh pueden incorporar expresiones regulares en sus pegotes (pruebe por ejemplo:ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
)Respuestas:
bash
inicialmente fue diseñado a finales de los 80 como un clon parcial deksh
algunas características interactivas de csh / tcsh.Los orígenes del globbing se deben encontrar en los caparazones anteriores sobre los que se basa.
ksh
en sí es una extensión del shell Bourne. El shell Bourne en sí (lanzado por primera vez en 1979 en Unix V7) fue una implementación limpia desde cero, pero no se apartó por completo del shell Thompson (el shell de V1 -> V6) e incorporó características del shell Mashey.En particular, los argumentos de comando todavía estaban separados por espacios en blanco,
|
ahora era el nuevo operador de tubería pero^
todavía era compatible como una alternativa (y también explica por qué lo hace[!a-z]
y no[^a-z]
),$1
seguía siendo el primer argumento para un script y la barra diagonal inversa seguía siendo el carácter de escape . Muchos de los operadores regexp (^\|$
) tienen un significado especial propio en el shell.El shell Thompson se basó en una utilidad externa para el globbing. Cuando se
sh
encuentra sin comillas*
,[
o?
s en el comando, ejecutaría el comandoglob
.terminaría ejecutando glob como:
y glob terminaría ejecutándose
rm
con la lista de archivos que coinciden con ese patrón.correría
glob
como:Lo
*
anterior se ha citado estableciendo el 8vo bit en ese carácter, evitando que loglob
trate como un comodín.glob
luego eliminaría ese bit antes de llamargrep
.Para hacer el equivalente con regexps, eso habría sido:
O:
para excluir archivos de puntos.
La necesidad de escapar de los operadores, ya que funcionan como caracteres especiales de shell, el hecho de que
.
, común en los nombres de archivo es un operador regexp, hace que no sea muy apropiado hacer coincidir los nombres de archivo y complicado para un principiante. En la mayoría de los casos, todo lo que necesita son comodines que puedan reemplazar uno (?
) o cualquier número (*
) de caracteres.Ahora, diferentes shells agregaron diferentes operadores de globbing. Hoy en día, los globos ksh y zsh (y hasta cierto punto,
bash -O extglob
que implementan un subconjunto de globos ksh) son funcionalmente equivalentes a expresiones regulares con una sintaxis que es menos engorrosa de usar con los nombres de archivo y la sintaxis de shell actual. Por ejemplo, enzsh
(con la extensión Extendedglob), puede hacer:si desea (poco probable) que coincida con los nombres de archivo que consisten en secuencias
a
seguidas de.txt
. Más fácil queecho (^a*\.txt$)
(aquí usando llaves como una forma de aislar a los operadores de expresiones regulares de los operadores de shell que podrían haber sido una forma en que los shells podrían lidiar con eso).Para archivos mpg (sin distinción entre mayúsculas y minúsculas) cuyo nombre base es foo, bar o un número decimal del 1 al 20 ...
ksh93
ahora también puede incorporar expresiones regulares (básicas, extendidas, perl-like o "aumentadas") en sus globos (aunque es bastante defectuoso) e incluso proporciona una herramienta para convertir entre glob y regexp (printf %R
,printf %P
):al partido (no oculta) txt con E XTended expresiones regulares, entre mayúsculas i nsensitively.
fuente
~(opt:pat)
ninguna de las opciones en mayúscula. Tal vezprint -r -- ~(Ei).*\.txt$
. Poner el patrón dentro parece ser útil solo para evitar tener que activar una opción y luego desactivarla durante parte de un patrón. Curiosamente, puedes mezclar y combinar múltiples lenguajes de patrones dentro del mismo globo.~(Ki)*.~(E)txt$
es equivalente. (Al final, todo se convierte en expresiones regulares y se pasa internamente al motor de expresiones regulares de libast).~(Ei:.*\.txt)
funciona para mí incluso con versiones de 15 años como ksh93 o +.~(E)x
y~(E:x)
es que este último está anclado (coincidex
solo mientras que el anterior coincide con cualquier cosa que contengax
), que puede ser el tipo de problema con el que se encontró (usar~(-lr)~(E:x)
para eliminar el anclaje,~(E-lr:x)
no funcionará). En cualquier caso, estoy de acuerdo en que es bastante defectuoso, incluso en la última versión.Kleene introdujo los idiomas regulares en 1956. El documento seminal no tenía la notación moderna completa para las expresiones regulares, pero sí introdujo la "estrella de Kleen": que
A*
significa "cualquier número de repeticiones deA
". En la próxima década, surgieron algunas notaciones más o menos estándar, en particular.
para un carácter arbitrario y?
para significar que el carácter anterior es opcional.La notación global de Bash se deriva del
glob
comando introducido en Unix v1 en 1971. En ese momento, la aplicación global fue realizada por un programa separado; Más tarde se trasladó a la cáscara. Elglob
comando inicial tiene?
que significar "cualquier carácter" y*
significa "cualquier secuencia de caracteres". No sé por qué los personajes fueron elegidos;?
es bastante intuitivo y*
puede haberse inspirado en el de las expresiones regulares.Globbing no pretendía ser tan general como las expresiones regulares, y las expresiones regulares no estaban muy extendidas en ese momento, por lo que no hubo un llamado a unificar los conceptos. Desde el principio, había incompatibilidades sintácticas, con
?
,.
y*
significa cosas diferentes en patrones de nombre de archivo y en las expresiones regulares.Los proyectiles modernos, como bash, se expanden en los patrones globales, pero fue una evolución gradual que mantuvo la compatibilidad con versiones anteriores. Ksh88 (la versión de 1988 del shell Korn ) introdujo una sintaxis extendida para patrones de shell, que no podía ser la misma sintaxis que las expresiones regulares habituales, pero estaba fuertemente inspirada por ella:
*(PATTERN)
significar cualquier número de repeticiones dePATTERN
,@(PATTERN1|PATTERN2)
significar "PATTERN1
oPATTERN2
", etc.Las versiones modernas de bash (desde 2.02) admiten los patrones extendidos de ksh88, si publica
shopt -s extglob
primero.fuente
extglob
opción se introdujo en bash 2.02 en algún lugar alrededor de 1998. Zsh adquirióksh_glob
en la serie 3.1 en algún lugar al mismo tiempo. Zsh tiene muchas extensiones propias (algunas requieren laextended_glob
opción).bash
, a diferencia deksh
, extglob hace que bash no sea compatible con POSIX porque no está deshabilitado en las variables. Enksh
, sevar='@(*)'; echo $var
expande a todos los nombres de archivo en el directorio actual que comienzan@(
y terminan)
como POSIX lo requiere, mientras que enbash -O extglob
él se expande a todos los archivos. (aún así, uno puede considerar que el comportamiento bash tiene más sentido aquí (y el comportamiento ksh es bastante doloroso cuando desea tener patrones en las variables)). Esa sintaxis global es muy incómoda debido a eso (compatibilidad POSIX / Bourne). Comparar con zsh globos extendidos.Razón histórica: SI. Referencia:
http://en.wikipedia.org/wiki/Glob_(programming)#Origin
Solo para mostrar la divergencia, aquí hay un ejemplo bueno y fácil:
a*
a
y luego lo que sea (a, ab, abca ...)a
(a, aa, aaa ...)Estoy de acuerdo en que esta discrepancia en el significado es muy confusa para los nuevos usuarios.
El globbing es quizás más fácil de entender para los recién llegados, pero también es una construcción menos poderosa.
fuente