buscar -exec con comodín

buscar -exec con comodín

Estoy intentando utilizar bash 'find' para procesar todas las carpetas que contienen un archivo .log y obtener sus tamaños. Sin embargo, el comodín no funciona como se esperaba. Esto no devuelve nada:

find . -type d -exec test -e '{}/*.log' \; -exec du -d0 '{}' \;

sin embargo, si lo reemplazo *.logcon foo.log, funciona como se esperaba para los directorios que contienen ese nombre de archivo.

Basado en algunas publicaciones SE similares, probé:

find . -type d -exec bash -c 'test -e "{}/*.log"' \; -exec du -d0 '{}' \;
find . -type d -exec bash -c 'test -e "$1/*.log"' '{}' \; -exec du -d0 '{}' \;

pero esos no funcionan mejor.

Respuesta1

Cuando find … -exec test -e '{}/*.log'estás pasando una cadena como something/*.log, test¿dónde *está?literal. Ninguna herramienta lo trata como un comodín. Algunas implementaciones de findni siquiera se expandirán {}si es parte de un argumento (en lugar de {}ser un argumento completo).

Uno de sus intentos posteriores se incrusta {}en el código del shell.Nunca incrustar {}en el código shell. El otro intento es mejor en este asunto, estás cerca de una solución. Esta voluntadun pocotrabajar:

# still flawed though
find . -type d -exec bash -c 'test -e "$1/"*.log' bash '{}' \; -exec du -d0 '{}' \;

Ver¿Cuál es el segundo pez sh -c 'some shell code' sh?. Sin embargo, la "solución" principal es no citar el asterisco en el código del shell. De esta manera, es un comodín en el caparazón interno (pero no en el caparazón externo, allí está correctamente entre comillas simples). El problema es que *.logpuede expandirse a más de una palabra (si hay muchos archivos coincidentes) y este caso interrumpirá la testinvocación.

El siguiente código encontrará directorios con *.logarchivos:

find . -type d -exec sh -c '
   for f in "$1/"*.log; do test -e "$f" && exit 0; done; exit 1
' sh {} \; -print

El código es portátil. No hay necesidad de internal bash, shdebería ser más rápido. Reemplace -printcon -exec du …si lo desea.

Esto funciona devolviendo éxito ( exit 0) desde el shell interno tan pronto como testse confirma la existencia de algún archivo coincidente¹. Los archivos coincidentes aún no probados (si los hay) no se probarán en vano, esto ahorra tiempo. Si no hay coincidencia, entonces el patrón permanecerá literal, testfallará y todo el shell saldrá con falla ( exit 1). Recuerde -execque también es una prueba, por lo que afecta si se realiza -print(o -exec du …lo que ponga allí).


Otro enfoque puede ser permitirse findencontrar archivos coincidentes con

find . -name '*.log' … -print

y analizar su salida para aislar los nombres de los directorios, finalmente usarlos xargscon du. Los directorios podrían aparecer varias veces, las nuevas líneas en los nombres de rutas requerirían código no portátil (comenzando desde -print0). Creo que esto sería innecesariamente complicado. Encontrar directorios parece superior.


¹ La nota test -ete indica si hay un archivoque puede ser un directorio o lo que sea. Para confirmar la existencia de un archivo normal, utilice test -f.

Respuesta2

Sería más fácil buscar/escanear archivos de registro y luego recopilar los nombres de directorio únicos.

Este findcomando debería extraer los directorios y agregarlos uniqpara eliminar duplicados. Las banderas -z/ -0ayudan a garantizar que las rutas con nuevas líneas/espacios/comillas se analicen sin problemas:

find . -type f -name \*.log -exec dirname -z {} \+ | uniq -z | xargs -0 -r du -d0

Agregue | sort -rn |headsi busca el mayor uso de disco.

información relacionada