
Quería recuperar todos los archivos .txt usando el carácter comodín '*'.
Probé este comando (y también sin las comillas " ") pero fallé.
ls | grep "*.txt"
Lo interesante es que si pongo otro carácter en el comando grep correspondiente a un archivo .txt en el directorio, funciona
>>ls | grep s*.txt
sample.txt
Sé que ls *.txt
funcionará, pero me sorprendió un poco la naturaleza del comando grep. ¿Alguien podría ayudarme por qué sucede esto?
¿Es por el hecho de que grep usa expresiones regulares? Por favor ayuda.
Respuesta1
En expresiones regulares, *
significa "cualquier número del elemento anterior", no "cualquier número de caracteres", como ocurre en los patrones de shell. Y .
significa "cualquier carácter". Entonces, para buscar "cualquier cosa, seguido de literal .txt
", usarías .*\.txt
. O simplemente \.txt
, ya que normalmente las coincidencias de expresiones regulares buscan la coincidencia en cualquier parte de la línea. Por otra parte, \.txt
también coincidiría con un nombre de archivo como foo.txtgz
, ya que .txt
no tendría que estar al final. Deberías \.txt$
bloquear el patrón hasta el final de la línea.
La expresión regular *.txt
no tiene sentido, es un error o busca un asterisco literal, según la implementación y si está utilizando expresiones regulares básicas ( grep
) o extendidas ( grep -E
). Lo mejor es no usarlo.
Por otro lado, s*.txt
buscaría "cualquier número de letras s
, luego cualquier carácter y luego literal txt
". Esa es una expresión regular más válida, pero... todavía no coincide sample.txt
.
En cambio, lo que sucede en su segundo comando es que, debido a que s*.txt
no está entre comillas, el shell se expande s*.txt
antes de grep
verlo. Si el único archivo coincidente es sample.txt
, entonces grep
lo buscará en la salida de ls
. (Si hubiera varios nombres de archivos coincidentes, el primero se tomaría como patrón y el resto como nombres de archivos para grep
leer. En ese caso, se ignoraría la entrada de la tubería).
Pero ls
también puede tomar una lista de archivos, así que si bien puedes usar
ls | grep '\.txt'
para obtener cualquier .txt
archivo, probablemente sería más fácil usar
ls *.txt
en cambio.
Respuesta2
Esto se debe en parte a que grep
utiliza expresiones regulares (de hecho, eso es lo que re
significa el nombre; es la abreviatura degramoglobalrregularmiexpresiónpagimpresión).
El *
comodín en las expresiones regulares es diferente del *
comodín en el shell global.
En expresiones regulares, *
significa "cero o más del objeto definido anteriormente". Sin embargo, .
estambiénun comodín, que significa "un carácter".
En shell globs, *
significa "cero o más caracteres". .
no es un comodín en absoluto.
Cuando grep
busca el patrón "*.txt"
, busca cero o más de cualquier cosa, seguido exactamente de un carácter más, seguido de la cadena literal txt
.
Cuando buscas grep
el patrón "s*.txt"m you are looking for a literal
s , followed by zero or more
s s, followed by any character, followed by the literal string
txt`.
Es por eso que algo común que encontrarás en las expresiones regulares es .*
, que significa "uno de cualquier carácter seguido de cero o más de cualquier carácter". Regexese para "literalmente cualquier combinación de caracteres distintos de cero caracteres".
Cuando le ls *.txt
dice al shell "Busque cualquier nombre de archivo que coincida con el patrón global *.txt
, enumerelos aquí y proporciónelos como argumentos para el ls
comando.
Respuesta3
tenga en cuenta que grep está buscando el archivocontenidomientras que el primer argumento es el PATRÓN de búsqueda y otros argumentos se interpretan como ARCHIVOS para examinar
se vuelve más claro para usted cuando usa grep -H -o
banderas o coloca grep
un script dentro y lo ejecuta conbash -x script
para ver cómo se expandieron los globos de shell antes de pasarlos como argumentos.