¿Cómo usar grep en todos los archivos de forma no recursiva en un directorio?

35

Quiero buscar una cadena de texto en todos los archivos en un directorio (y no en sus subdirectorios; sé que la -ropción lo hace, pero eso no es lo que quiero).

  1. Corriendo

    grep "string" /path/to/dir
    

    se supone que es capaz de hacer esto, lo he leído, pero me da el error:

    grep: dir: es un directorio

  2. A continuación, intenté ejecutar grepen varios archivos.

    grep "string" .bashrc .bash_aliases funciona perfectamente.

    grep "string" .bash* Funciona según lo previsto también.

    grep "string" * me da los errores:

    grep: data: Is a directory
    grep: Desktop: Is a directory
    grep: Documents: Is a directory
    grep: Downloads: Is a directory
    ...
    

Solo se imprimen los errores, no obtengo las líneas coincidentes. Intenté usar la -sopción, pero fue en vano.

Entonces, mis preguntas:

  1. ¿Por qué no puedo usar grepen un directorio, como en (1), cuando debería poder? Lo he visto en muchos ejemplos en Internet.
    Editar : cuando digo "usar grep en un directorio", me refiero a "buscar en todos los archivos de ese directorio, excepto sus subdirectorios". Creo que esto es lo que hace grep cuando le pasa un directorio en lugar de un archivo. ¿Soy incorrecto?

  2. Por favor, dame una explicación sobre el funcionamiento de grepeso explicaría el comportamiento de los comandos en (2).
    Editar : Déjame ser más específico. ¿Por qué el uso de comodines para especificar múltiples archivos para buscar trabajo .bash*y no con *o incluso ./*?

  3. ¿Cómo puedo buscar todos los archivos en un directorio (y no en sus subdirectorios) usando grep?

John Red
fuente
También confía en los comodines que se expanden en el shell, como *, conocido como globbing. Globbing no incluye nombres de archivo que comienzan con un punto .bashrccomo el estándar. Puede establecer opciones de shell para que incluya estos archivos, pero puede meterse en un lío si no sabe lo que está haciendo. Puede encontrar una buena guía para comprender el gloging aquí mywiki.wooledge.org/glob
Arronical
No sé por qué, pero siempre he hecho glob en archivos ocultos, y siempre ha funcionado. No he cambiado ninguna configuración o algo. Como señalé en (2), también funciona con grep "string" .bash*.
John Red
Lo siento, mi último ejemplo fue incorrecto. También puede buscar en archivos ocultos y suprimir el "es un directorio" porque Linux técnicamente ve los directorios como un tipo diferente de archivo. El comando sería entonces: grep "string" * .* 2>/dev/nullogrep -s "string" * .*
Terrance
También este stackoverflow.com/q/9217185/3701431
Sergiy Kolodyazhnyy

Respuestas:

41

En Bash, un globo no se expandirá a archivos ocultos, por lo que si desea buscar todos los archivos en un directorio, debe especificar los archivos ocultos .*y no ocultos *.

Para evitar los errores "Es un directorio", puede usar -d skip, pero en mi sistema también recibo un error grep: .gvfs: Permission denied , por lo que sugiero usar -s, que oculta todos los mensajes de error.

Entonces, el comando que está buscando es:

grep -s "string" * .*

Si está buscando archivos en otro directorio:

grep -s "string" /path/to/dir/{*,.*}

Otra opción es usar la dotglobopción de shell, que hará que un globo incluya archivos ocultos.

shopt -s dotglob
grep -s "string" *

Para archivos en otro directorio:

grep -s "string" /path/to/dir/*

† Alguien mencionó que no debería recibir este error. Puede que tengan razón: leí un poco pero no pude entenderlo.

wjandrea
fuente
¿Hay alguna razón para el espacio entre *y .*?
Hashim
2
@Hashim Compare la salida echo * .*y echo *.*ejecute en su directorio de inicio, y la diferencia debería ser obvia. De lo contrario, LMK y lo explicaré.
wjandrea
Interesante, echo *muestra archivos y carpetas echo *.*no ocultos, echo .*muestra archivos no ocultos, muestra todos los archivos y echo * .*muestra todos los archivos y directorios. Pero, ¿por qué la razón del espacio entre los dos en el último caso? Se siente desordenado para mí. ¿No hay una forma de combinar los dos para obtener los mismos resultados? O de lo contrario, ¿hay una explicación de la sintaxis de por qué los dos deben separarse aquí, o es * .*un caso excepcional?
Hashim
1
@Hashim No estoy seguro de cómo llegaste a esas conclusiones, así que déjame explicarte. Primero, los directorios son archivos en este contexto. En globos, *representa todos los archivos no ocultos (es decir, nombres de archivo que no comienzan con un punto); .*representa todos los archivos ocultos (es decir, nombres de archivo que no empiezan por un punto); y *.*representa todos los archivos no ocultos que contienen un punto. En echo * .*, los dos globos deben estar separados porque son globos diferentes: uno para no oculto, uno para oculto. Aunque, como escribí en mi respuesta, puede *incluir archivos ocultos activando la dotglobopción de shell.
wjandrea
1
El uso *.*es común en Windows (DOS) como una forma de listar todos los archivos, pero en * nix solo incluirá archivos con un punto, por lo que no tiene sentido en * nix. En su lugar, utiliza *para enumerar todos los archivos, excepto los archivos ocultos, y .*para enumerar los archivos ocultos.
thomasrutter
11

Necesita la -d skipopción agregada.

  1. Grep está buscando dentro de los archivos. Puede buscar de forma recursiva, como dijo, si desea buscar archivos dentro de un directorio.

  2. Por defecto, grep leerá todos los archivos y detectará los directorios. Debido a que, de manera predeterminada, no ha definido qué hacer con los directorios con la -dopción, da un resultado de error.

  3. Buscar solo dentro del directorio padre sería `grep -d skip" string "./*

anónimo2
fuente
Para obtener más información sobre grep, consulte man grep.
anonymous2
(a) Por favor vea la edición. (b) El uso -d skipno funciona; es básicamente lo mismo que -s; También, vea la edición. (c) No, grep -d skip "string" ./*tampoco funciona.
John Red
7

Los veteranos probablemente harían esto:

find . -type f -print0 | xargs -0 grep "string"
dathompson
fuente
3
¿Por qué no find . -type f -exec grep string {} +?
wchargin
55
Tu también quieres -maxdepth 1.
wchargin
@wchargin: si quieres el nombre del archivo en la salida cuando solo hay un archivo que creo que quieresfind . -type f -maxdepth 1 -exec grep string /dev/null {} +
Gregory Nisbet
1
@ GregoryNisbet: solo pasa -Ha grep.
wchargin
2

Reformulación: ¿desea grep los archivos en un nivel de subdirectorio, pero no recurrir a través de todos los subdirectorios?

grep forthis  *  */*

O si no quieres los archivos en el directorio actual

grep forthis  */*

Tenga en cuenta que esto no encontrará directorios que comiencen con un punto.

grep forthis  .*/*    */*   

Debería hacer ese trabajo.

También hay -maxdepthy -mindepthparámetros disponibles restricción al findcomando también.

Criggie
fuente
¿No grep forthis */*buscaría archivos tanto en el directorio actual como en uno abajo?
Hashim
@Hashim nope en su mayoría, porque */*solo combina cosas con una barra. Si tuviera un archivo nombrado a/ben el directorio actual, entonces '* / * coincidiría con eso.
Criggie
0

Aquí hay un ejemplo para omitir directorios sin omitir todos los errores:

grep --directories='skip' 'searchString' *
Mojtaba Rezaeian
fuente