eliminar archivos más antiguos

9

Estoy tratando de eliminar archivos antiguos del directorio y dejar solo 3 archivos más nuevos.

cd /home/user1/test

while [ `ls -lAR | grep ^- | wc -l` < 3 ] ; do

    rm `ls -t1 /home/user/test | tail -1`
    echo " - - - "

done

algo está mal con la declaración condicional.

d3vil0
fuente

Respuestas:

9

Si desea recorrer los archivos, nunca usels *. tl; dr Hay muchas situaciones en las que terminaría borrando el archivo incorrecto, o incluso todos los archivos.

Dicho esto, desafortunadamente esto es algo complicado de hacer bien en Bash. Hay una respuesta que funciona en una pregunta duplicada incluso más antiguafind_date_sorted que puedes usar con pequeñas modificaciones:

counter=0
while IFS= read -r -d '' -u 9
do
    let ++counter
    if [[ counter -gt 3 ]]
    then
        path="${REPLY#* }" # Remove the modification time
        echo -e "$path" # Test
        # rm -v -- "$path" # Uncomment when you're sure it works
    fi
done 9< <(find . -mindepth 1 -type f -printf '%TY-%Tm-%TdT%TH:%TM:%TS %p\0' | sort -rz) # Find and sort by date, newest first

* No se ofendan, chicos ls. Pero realmente no es seguro.

Editar: Nuevofind_date_sorted con pruebas unitarias.

l0b0
fuente
Secundo la parte sobre no analizar ls. Además, el guión es ordenado, pero creo que se podría hacer de una sola vez, déjame comprobar ...
rahmu 05 de
Bueno, siempre puedes compactar el código Bash en una sola línea, pero el problema es si será legible :)
l0b0
2
Si puedo robar sin piedad una idea de @ Peter.O, prueba ((++counter>3))como prueba. Es muy sucinto. En cuanto a los oneliners: si la brevedad es una preocupación, envuelva el código en una función, entonces no se preocupe por eso.
Sorpigal
@Sorpigal Neat shortcut
l0b0
5

Para eliminar todos los archivos, excepto los 3 más nuevos, utilizando un zsh glob, puede usar Om(O mayúscula) para ordenar los archivos del más antiguo al más nuevo y un subíndice para obtener los archivos que desee.

rm ./*(Om[1,-4])
#    | ||||  ` stop at the 4th to the last file (leaving out the 3 newest)
#    | |||` start with first file (oldest in this case)
#    | ||` subscript to pick one or a range of files
#    | |` look at modified time
#    | ` sort in descending order
#    ` start by looking at all files

Otros ejemplos:

# delete oldest file (both do the same thing)
rm ./*(Om[1])
rm ./*(om[-1])

# delete oldest two files
rm ./*(Om[1,2])

# delete everything but the oldest file
rm ./*(om[1,-2])
Mario Lopez
fuente
5

Con mucho, el método más fácil es usar zsh y sus calificadores globales : Ompara ordenar disminuyendo la edad (es decir, la más antigua primero) y [1,3]retener solo las tres primeras coincidencias.

rm ./*(Om[1,3])

Vea también ¿Cómo filtro un globo en zsh para más ejemplos?

Y preste atención al consejo de l0b0 : su código se romperá horriblemente si tiene nombres de archivo que contienen caracteres especiales de shell.

Gilles 'SO- deja de ser malvado'
fuente
Woa woa sostenga el tren, ¿es realmente una solución completa en 1 línea?
MetaGuru
2
@ Ryan Eso es zsh para ti.
Gilles 'SO- deja de ser malvado'
1

Puede usar la siguiente función para obtener el archivo más nuevo en un directorio:

newest_in() 
{ 
    local newest=$1

    for f;do [[ $f -nt $newest ]] && newest="$f"; done;

    printf '%s\n' "$newest"
}

Dele un conjunto diferente de archivos al extraer el archivo más nuevo después de cada iteración.

Consejo: Si mantiene el conjunto inicial de archivos en una matriz llamada "$ {files [@]}", guarde el índice del archivo más nuevo encontrado y unset 'files[index]'antes de la siguiente iteración.

Uso: newest_in [set of files/directories]

Salida de muestra:

[rany$] newest_in ./*
foo.txt
[rany$]
Rany Albeg Wein
fuente
-1

Primero, la -Ropción es para la recursividad, que probablemente no sea lo que desea, que también buscará en todos los subdirectorios. Segundo, el <operador (cuando no se ve como redirección) es para la comparación de cadenas. Probablemente quieras -lt. Tratar:

while [ `ls -1A | grep ^- | wc -l` -lt 3 ]

Pero usaría encontrar aquí:

while [ `find . -maxdepth 1 -type f -print | wc -l` -lt 3 ]
Arcege
fuente
Ambos fallarán si uno o más de los nombres de archivo contienen un '$ \ n'.
Rany Albeg Wein
-1

Sé que es un pecado analizar ls, pero ¿qué pasa con esto?

find . -type f -maxdepth 1 | xargs ls -ltr | sed '1,3d' | awk '{print $9}' | xargs rm

Una prueba rápida con 5 archivos vacíos:

$ >1
$ >2
$ >3
$ >4
$ >5
$ find . -type f -maxdepth 1 | xargs ls -lt | sed '1,3d' | awk '{print $9}' | xargs rm
$ ls -1
3
4
5
Rudolf Adamkovic
fuente
Éste fallará por dos razones: analizar la lssalida y usar findy xargsjuntos de manera incorrecta. Si se combinan findy xargste recomiendo que el uso finds -print0y, en consecuencia xargss -Oopciones. Lea sobre Uso de Buscar para obtener más información sobre el tema. También es posible que desee echar un vistazo y leer sobre por qué Analizar ls es muy malo.
Rany Albeg Wein
-2

Este one-liner lo hace todo lo que pienso:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"
Salva
fuente
ls es una herramienta para mirar interactivamente la información del archivo. Su salida está formateada para humanos y causará errores en los scripts. Usa globos o encuentra en su lugar. Comprenda por qué: mywiki.wooledge.org/ParsingLs
Rany Albeg Wein
-2

Aquí hay una solución:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)
babak
fuente
1
@bakbak ls es una herramienta para mirar interactivamente la información del archivo. Su salida está formateada para humanos y causará errores en los scripts. Mira aquí para entender por qué . Hablando específicamente sobre su respuesta: esta se romperá si uno o más de los archivos contienen un carácter $ '\ n'. Además, la sustitución de comandos (es decir, $ (...)) carece de comillas dobles, lo que plantea otro tema importante: la división de palabras .
Rany Albeg Wein