Respostas:
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 ls
antes. Mas isso realmente não é seguro.
Edit: Novofind_date_sorted
com testes de unidade.
((++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.
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])
De longe, o método mais fácil é usar o zsh e seus qualificadores globais : Om
classificar 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.
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$]
Primeiro, a -R
opçã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 ]
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
ls
saída e usando find
e xargs
juntos da maneira errada. Se você combinar find
e xargs
eu recomendo que você use as opções find
s -print0
e, consequentemente, xargs
s -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.
Este one-liner faz tudo o que eu penso:
ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"
Aqui está uma solução:
rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)