grep no da resultados para un directorio pasado en una variable

grep no da resultados para un directorio pasado en una variable

Estoy intentando escribir un bashscript que busque en el contenido de los archivos en un árbol de directorios específico la presencia de una subcadena específica.

Usar grepla función recursiva de 's por sí sola no es suficiente, ya que potencialmente necesito iterar sobre el /directorio (y todos los subdirectorios) de un sistema, lo que hace que grepse quede sin memoria y aborte. Por lo tanto, decidí obtener una lista de todos los directorios y subdirectorios en el árbol de directorios especificado utilizando findlas siguientes variables que denotan los argumentos pasados ​​al script.

searchdir=$HOME     # passed in a script argument
searchstr="secret"  # passed in a script argument

Llamo a la findutilidad y almaceno el resultado en un archivo temporal.

TF=$(mktemp)
find ${searchdir} -type d 1>$TF 2>/dev/null

Con la lista de todos los directorios en el archivo temporal, procedo a iterar sobre las líneas de este archivo usando un while-dobucle con la intención de realizar una búsqueda en todos los archivos en cada directorio. Para grep, utilizo el formato de parámetros proporcionado enesta respuestapara buscar todos los archivos, incluidos los ocultos, en un único directorio.

cat $TF | while read line || [[ -n $line ]];
do
    grepdir="${line}/{*,.*}"
    grep -sHn "${searchstr}" ${grepdir}
done

... sin embargo, ese código no produce ningún resultado.

Comprobé que...

Contiene ${TF}la lista correcta de todos los directorios. Generar la ${grepdir}variable proporciona el resultado que espero encontrar.

/home/user/{*,.*}
/home/user/.ssh/{*,.*}
/home/user/test/{*,.*}
# ... and so on

Si ejecuto el grepcomando con un directorio codificado, particularmente el ~/test/directorio, que contiene dos archivos de prueba con la cadena que se supone que debe encontrar

grep -sHn "${searchstr}" /home/user/test/{*,.*}

... genera correctamente los dos archivos que contienen la subcadena "secreto".

/home/user/test/asdf:7:secret
/home/user/test/test.txt:5:asdfasfdsecretaasdfafd

Un formato que me funciona es el que se menciona originalmente en elrespuesta que discute el uso recursivo degrep. Si hago esto:

cat $TF | while read line || [[ -n $line ]];
do
    grep -rn "${line}" -e "${searchstr}"
done

... Obtengo algunos resultados (técnicamente correctos, pero con muchas entradas duplicadas), pero dado que grepestá procesando los directorios de forma recursiva y tengo una lista de todos los directorios, seguramente obtendré los mismos resultados muchas veces y en directorios como el directorio raíz antes mencionado grepfallará por completo, que es lo que estoy tratando de evitar.


Probablemente también debería mencionar que mis trucos desesperados para hacerlo funcionar, como pasar $(echo "${grepdir}")el parámetro, tampoco produjeron resultados.

Lo más probable es que haya una idea errónea en mi forma de pensar o comprender bash. ¿No debería bashexpandir la ${grepdir}variable antes de realizar una llamada grep? ¿Dónde va mal mi guión?

Respuesta1

Regla número 1: cuando un comando o secuencia de comandos no hace lo que usted desea, mire los mensajes de error.  No los arrojes  /dev/null.

Estás recibiendo mensajes de error como

grep: /home/user/{*,.*}: No such file or directory
grep: /home/user/.ssh/{*,.*}: No such file or directory
grep: /home/user/test/{*,.*}: No such file or directory

pero no los estás viendo.

si miramosfiesta(1), vemos

La expansión se realiza en la línea de comando después de dividirla en palabras. Se realizan siete tipos de expansión: expansión de llaves, expansión de tilde, expansión de parámetros y variables, sustitución de comandos, expansión aritmética, división de palabras y expansión de nombres de rutas.

El orden de las expansiones es: expansión de llaves; expansión de tilde, expansión de parámetros y variables, expansión aritmética y sustitución de comandos (realizada de izquierda a derecha); división de palabras; y expansión del nombre de ruta.

La parte importante para su situación es que la expansión de la llave ocurre antes de la expansión variable. Entonces, si dijiste

grep -sHn "${searchstr}" "${line}"/{*,.*}

entonces

  • la expansión de llaves convertiría el último token en "${line}"/*y "${line}"/.*,
  • la expansión variable convertiría lo anterior en /home/user/*y /home/user/.*, y luego
  • La expansión del nombre de ruta convertiría lo anterior en una lista de nombres de archivos.

Pero, cuando dices

grep -sHn "${searchstr}" ${grepdir}

entonces

  • La expansión variable convierte el último token en /home/user/{*,.*},

y entonces ya es demasiado tarde para que se produzca la expansión del aparato ortopédico.  grepbusca un archivo llamado literalmente /home/user/{*,.*}.


PD

grep -sHn "${searchstr}" "${line}/{*,.*}"

tampoco funcionaría, porque las comillas evitarían que se produjera la expansión de llaves y la expansión del nombre de ruta.

PPS No necesitas todos esos aparatos ortopédicos;

grep -sHn "$searchstr" "$line"/{*,.*}

estaría bien.

Respuesta2

La razón por la que grep aborta cuando se repite en todo el sistema probablemente no sea que no pueda hacer frente a la cantidad de datos, sino que tropiece con uno u otro pseudo archivo o archivo de dispositivo en /proc, /sys o /dev. Puede excluir los directorios infractores con la --excludeopción en la línea de comando.

La razón por la que no expande los comodines es porque están citados en esta línea:

    grepdir="${line}/{*,.*}"

Cambiarlo a esto probablemente ayudará a que se expandan.

    grepdir="${line}/"{*,.*}

Otra forma de lograr esto (con menos secuencias de comandos de su parte) sería seleccionar los archivos usando findy canalizando las rutas de los archivos para xargssu procesamiento:find / ... -print 0 | xargs -0 ...

Sin embargo, de cualquier manera probablemente seguiría tropezando con cualquier archivo con el que tropezó el grep recursivo original, a menos que los excluya.

información relacionada