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 -10sintaxis 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 rmcorre el riesgo de
xargssoluciona 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 rmarchivo 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
heady xargsdar errores. Las opciones correctas son head -n 10y xargs rm -f. El comando completo esls -1tr ./ | head -n 10 | xargs rm -rf
ls -1tres 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 -1opción (número uno) imprime cada archivo en una sola línea, para estar seguro. La -fopción rmle dice que ignore los archivos inexistentes para cuando lsno devuelve nada.
/path/to/your/logssolo 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 +11solo y verifique si el resultado es correcto.
+antes del número. No tailimprime 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.
lsimprime un nombre de archivo, no una ruta, por rm -flo que intentará eliminar los archivos en el directorio actual
Aparentemente analizar lses 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 -deletesolo elimina archivos modificados exactamente hace 10 días. Los archivos más antiguos no se eliminarán. -mtime +11 -deleteeliminará los archivos que se hayan modificado hace 11 o más días, dejando los últimos 10 días de archivos de registro.
%plugar de %Pes necesario printfpara 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 lspara realizar la clasificación, pero luego uso los archivos inodepara 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 *.tarenumera 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 -tcomando 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 VarNameal valor de $1. Se pueden crear múltiples variables de una vez. Esto se VarNameconvierte 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 lssalida de los nombres de archivos absolutos, al menos en "mi" bash :)