Estoy tratando de mantener un directorio lleno de archivos de registro manejables. Todas las noches, quiero eliminar todos menos los 10 más recientes. ¿Cómo puedo hacer esto en un solo comando?
Estoy tratando de mantener un directorio lleno de archivos de registro manejables. Todas las noches, quiero eliminar todos menos los 10 más recientes. ¿Cómo puedo hacer esto en un solo comando?
Respuestas:
Para una solución portátil y confiable, intente esto:
ls -1tr | head -n -10 | xargs -d '\n' rm -f --
La tail -n -10
sintaxis en una de las otras respuestas no parece funcionar en todas partes (es decir, no en mis sistemas RHEL5).
Y usar $()
o ``
en la línea de comando rm
corre el riesgo de
xargs
soluciona ambos problemas porque automáticamente calculará cuántos args puede pasar dentro del límite de caracteres, y con el -d '\n'
solo se dividirá en el límite de línea de la entrada. Técnicamente, esto todavía puede causar problemas para los nombres de archivo con una nueva línea en ellos, pero eso es mucho menos común que los nombres de archivo con espacios, y la única forma de evitar las nuevas líneas sería mucho más complicada, probablemente con al menos awk, si no es que perl.
Si no tiene xargs (¿antiguos sistemas AIX, tal vez?), Podría hacer un bucle:
ls -1tr | head -n -10 | while IFS= read -r f; do
rm -f "$f"
done
Esto será un poco más lento porque genera un rm
archivo separado para cada archivo, pero seguirá evitando las advertencias 1 y 2 anteriores (pero aún sufre de nuevas líneas en los nombres de archivo).
head(1)
página del manual:-n, --lines=[-]K print the first K lines instead of the first 10; with the leading '-', print all but the last K lines of each file
head
y xargs
dar errores. Las opciones correctas son head -n 10
y xargs rm -f
. El comando completo esls -1tr ./ | head -n 10 | xargs rm -rf
ls -1tr
es el número UNO, no la letra "L".
El código que desea incluir en su secuencia de comandos es
rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)
La -1
opción (número uno) imprime cada archivo en una sola línea, para estar seguro. La -f
opción rm
le dice que ignore los archivos inexistentes para cuando ls
no devuelve nada.
/path/to/your/logs
solo está hecho para que usted ingrese la ruta correcta. Para encontrar el error, ejecute las partes ls -t /path/...
y ls -t /path/... | tail -n +11
solo y verifique si el resultado es correcto.
+
antes del número. No tail
imprime los últimos n elementos, sino todos los elementos que comienzan desde el n °. Me registré nuevamente y el comando definitivamente debería eliminar solo los elementos anteriores a los 10 archivos más recientes en todas las circunstancias.
ls
imprime un nombre de archivo, no una ruta, por rm -f
lo que intentará eliminar los archivos en el directorio actual
Aparentemente analizar ls
es malo .
Si cada archivo se crea a diario y desea mantener los archivos creados en los últimos 10 días, puede hacer lo siguiente:
find /path/to/files -mtime 10 -delete
O si cada archivo se crea arbitrariamente:
find /path/to/files -maxdepth 1 -type f -printf '%Ts\t%P\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf
-mtime 10 -delete
solo elimina archivos modificados exactamente hace 10 días. Los archivos más antiguos no se eliminarán. -mtime +11 -delete
eliminará los archivos que se hayan modificado hace 11 o más días, dejando los últimos 10 días de archivos de registro.
%p
lugar de %P
es necesario printf
para que los archivos tengan la ruta completa. De lo contrario rm -rf
, no funciona.
He modificado el enfoque de Isaac un poco.
Ahora funciona con una ruta deseada:
ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
Desde aquí :
#! /bin/sh
# keepnewest
#
# Simple directory trimming tool to handle housekeeping
# Scans a directory and deletes all but the N newest files
#
# Usage: cleanup <dir> <number of files to keep>
#
# v 1.0 Piers Goodhew 1/mar/2007. No rights retained.
if [ $# -ne 2 ]; then
echo 1>&2 "Usage: $0 <dir> <number of files to keep>"
exit 1
fi
cd $1
files_in_dir=`ls | wc -l`
files_to_delete=`expr $files_in_dir - $2`
if [ $files_to_delete -gt 0 ]; then
ls -t | tail -n $files_to_delete | xargs rm
if [ $? -ne 0 ]; then
echo "An error ocurred deleting the files"
exit 1
else
echo "$files_to_delete file(s) deleted."
fi
else
echo "nothing to delete!"
fi
En Bash puedes probar:
ls -1t | (i=0; while read f; do
if [ $i -lt 10 ]; then
((i++))
continue
else
rm -f "$f"
fi
done)
Esto omite los 10 als más nuevos y elimina el resto. logrotate puede ser mejor, solo quiero corregir las respuestas incorrectas relacionadas con el shell.
No estoy seguro de que esto ayude a nadie, pero para evitar posibles problemas con los caracteres inestables que acabo de usar ls
para realizar la clasificación, pero luego uso los archivos inode
para la eliminación.
Para el directorio actual, esto mantiene los 10 archivos más recientes según la hora de modificación.
ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;
Necesitaba una solución elegante para el busybox (enrutador), todas las soluciones de xargs o array me resultaron inútiles; no hay tal comando disponible allí. find and mtime no es la respuesta adecuada, ya que estamos hablando de 10 elementos y no necesariamente de 10 días. La respuesta de Espo fue la más corta, más limpia y probablemente la más irreversible.
El error con espacios y cuando no se van a eliminar archivos simplemente se resuelve de la manera estándar:
rm "$(ls -td *.tar | awk 'NR>7')" 2>&-
Versión un poco más educativa: podemos hacerlo todo si usamos awk de manera diferente. Normalmente, uso este método para pasar (devolver) variables de awk a sh. Como leemos todo el tiempo que no se puede hacer, ruego diferir: aquí está el método.
Ejemplo para archivos .tar sin problemas con respecto a los espacios en el nombre del archivo. Para probar, reemplace "rm" con el "ls".
eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')
Explicación:
ls -td *.tar
enumera todos los archivos .tar ordenados por hora. Para aplicar a todos los archivos en la carpeta actual, elimine la parte "d * .tar"
awk 'NR>7...
salta las primeras 7 líneas
print "rm \"" $0 "\""
construye una línea: rm "nombre de archivo"
eval
lo ejecuta
Como estamos usando rm
, ¡no usaría el comando anterior en un script! El uso más sabio es:
(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))
En el caso de usar el ls -t
comando no hará ningún daño en ejemplos tan tontos como: touch 'foo " bar'
y touch 'hello * world'
. ¡No es que alguna vez creamos archivos con esos nombres en la vida real!
Nota al margen. Si quisiéramos pasar una variable al sh de esta manera, simplemente modificaríamos la impresión:
print "VarName="$1
para establecer la variable VarName
al valor de $1
. Se pueden crear múltiples variables de una vez. Esto se VarName
convierte en una variable sh normal y puede usarse normalmente en un script o shell después. Entonces, para crear variables con awk y devolverlas al shell:
eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"
Basado en la respuesta de Isaac Freeman, pero trabajando en cualquier directorio:
ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --
También puede establecer un prefijo, como $PATH_TO_DELETE/testFi*
Si utiliza *
después de la PATH
ls
salida de los nombres de archivos absolutos, al menos en "mi" bash :)