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 *.log
con 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 find
ni 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 *.log
puede expandirse a más de una palabra (si hay muchos archivos coincidentes) y este caso interrumpirá la test
invocación.
El siguiente código encontrará directorios con *.log
archivos:
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
, sh
debería ser más rápido. Reemplace -print
con -exec du …
si lo desea.
Esto funciona devolviendo éxito ( exit 0
) desde el shell interno tan pronto como test
se 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, test
fallará y todo el shell saldrá con falla ( exit 1
). Recuerde -exec
que 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 find
encontrar archivos coincidentes con
find . -name '*.log' … -print
y analizar su salida para aislar los nombres de los directorios, finalmente usarlos xargs
con 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 -e
te 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 find
comando debería extraer los directorios y agregarlos uniq
para eliminar duplicados. Las banderas -z
/ -0
ayudan 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 |head
si busca el mayor uso de disco.