remover arquivos mais antigos

9

Estou tentando excluir arquivos antigos do diretório e deixar apenas 3 arquivos mais recentes.

cd /home/user1/test

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

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

done

algo está errado com a declaração condicional.

d3vil0
fonte

Respostas:

9

Se você deseja fazer um loop sobre arquivos, nunca usels *. tl; dr Há muitas situações em que você acaba excluindo o arquivo errado ou mesmo todos os arquivos.

Dito isto, infelizmente, isso é algo complicado de se fazer no Bash. Há uma resposta de trabalho em uma pergunta duplicada ainda mais antiga,find_date_sorted que você pode usar com pequenas modificações:

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

* Sem ofensas, eu também usei lsantes. Mas isso realmente não é seguro.

Edit: Novofind_date_sorted com testes de unidade.

l0b0
fonte
Segundo a parte sobre não analisar ls. Além disso, o script é puro, mas acho que poderia ser feito em um forro de um, deixe-me ver ...
rahmu
Bem, você sempre pode código Bash compacto em um one-liner, mas a questão é se ele vai ser legível :)
l0b0
2
Se eu puder roubar impiedosamente uma idéia de @ Peter.O, tente ((++counter>3))como seu teste. É bem sucinto. Quanto aos oneliners: se a brevidade é uma preocupação, envolva o código em uma função, então não se preocupe.
precisa saber é o seguinte
@Sorpigal Neat atalho
l0b0
5

Para excluir todos os arquivos, exceto os três mais novos, usando o zsh glob, você pode usar Om(capital O) para classificar os arquivos do mais antigo para o mais novo e um índice para capturar os arquivos desejados.

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

Outros exemplos:

# 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
fonte
5

De longe, o método mais fácil é usar o zsh e seus qualificadores globais : Omclassificar por idade decrescente (ou seja, a mais antiga primeiro) e [1,3]reter apenas as três primeiras partidas.

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

Veja também Como filtrar uma glob no zsh para obter mais exemplos.

E siga o conselho do l0b0 : seu código será quebrado de forma horrível se você tiver nomes de arquivos que contenham caracteres especiais do shell.

Gilles 'SO- parar de ser mau'
fonte
Woa woa segurar o trem, isso é realmente uma solução completa em uma linha?
MetaGuru 15/05
2
@ Ryan Isso é zsh para você.
Gilles 'SO- stop be evil'
1

Você pode usar a seguinte função para obter o arquivo mais recente em um diretório:

newest_in() 
{ 
    local newest=$1

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

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

Dê a ele um conjunto diferente de arquivos, exulcando o arquivo mais recente após cada iteração.

Dica: Se você mantiver o conjunto inicial de arquivos em uma matriz chamada "$ {files [@]}", salve o índice do arquivo mais recente encontrado e unset 'files[index]'antes da próxima iteração.

Uso: newest_in [set of files/directories]

Saída de amostra:

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

Primeiro, a -Ropção é recursão, o que provavelmente não é o que você deseja - que também procurará em todos os subdiretórios. Segundo, o <operador (quando não está sendo visto como redirecionamento) é para comparação de cadeias. Você provavelmente quer -lt. Tentar:

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

Mas eu usaria find aqui:

while [ `find . -maxdepth 1 -type f -print | wc -l` -lt 3 ]
Arcege
fonte
Ambos falharão se um ou mais nomes de arquivos contiver um '$ \ n'.
precisa saber é o seguinte
-1

Eu sei que é um pecado analisar ls, mas e quanto a isso:

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

Um teste rápido com 5 arquivos vazios:

$ >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
fonte
Este falhará por dois motivos - Analisando a lssaída e usando finde xargsjuntos da maneira errada. Se você combinar finde xargseu recomendo que você use as opções finds -print0e, consequentemente, xargss -O. Leia sobre Como usar a localização para obter mais informações sobre o assunto. Você também pode dar uma olhada e ler sobre por que a análise de ls é muito ruim.
precisa saber é o seguinte
-2

Este one-liner faz tudo o que eu penso:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"
Salvo
fonte
ls é uma ferramenta para analisar interativamente as informações do arquivo. Sua saída é formatada para humanos e causará erros nos scripts. Use globs ou encontre. Entender o porquê: mywiki.wooledge.org/ParsingLs
Rany Albeg Wein
-2

Aqui está uma solução:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)
babak
fonte
11
O @bakbak ls é uma ferramenta para analisar interativamente as informações do arquivo. Sua saída é formatada para humanos e causará erros nos scripts. Olhe aqui para entender o porquê . Especificamente falando sobre sua resposta - essa será interrompida se um ou mais arquivos contiverem um caractere $ '\ n'. Além disso, a Substituição de Comando (ou seja, $ (...)) não possui aspas duplas, o que traz outro assunto importante - Divisão de Palavras !
precisa saber é o seguinte