Tenho o seguinte caminho:
/dir1/dir2/
Neste caminho, tenho os seguintes diretórios contendo vários detrius de aplicativos (não relevantes):
follower1234 1-Dec-2018
follower3456 2-Dec-2018
follower4567 3-Dec-2018
follower7890 9-Jan-2019
follower8901 10-Jan-2019
leader8765 4-Dec-2018
bystander6789 5-Dec-2018
Suponha que hoje seja 10 de janeiro de 2019.
Suponha que pode haver qualquer número de followerXXXX
diretórios leaderXXXX
e bystanderXXXX
.
O que eu quero é excluir todos os followerXXXX
diretórios, exceto o followerXXX
diretório mais recente, que tem mais de duas semanas.
Agora posso excluir todos os diretórios anteriores a uma determinada data . Mas essa não é a minha pergunta. Estou adicionando dois parâmetros adicionais.
Neste caso eu quero deletar:
follower1234 1-Dec-2018
follower3456 2-Dec-2018
follower4567 3-Dec-2018
Mas não
follower7890 9-Jan-2019
follower8901 10-Jan-2019
leader8765 4-Dec-2018
bystander6789 5-Dec-2018
ou seja, eu quero excluir arquivos
(a) correspondendo a um padrão
(b) mais de duas semanas
(c) não é o diretório mais recente que corresponde ao padrão (ou seja, mantenha o último)
Minha pergunta é: Como excluir todos os diretórios em um diretório com mais de 2 semanas, exceto o mais recente que corresponde a um padrão de arquivo?
Introdução
A pergunta foi modificada.
Minha primeira alternativa (o oneliner) não corresponde à nova especificação, mas salva o diretório mais recente entre os diretórios antigos o suficiente para serem excluídos (mais de 14 dias).
Eu fiz uma segunda alternativa, (o shellscript) que usa
@ segundos desde 1º de janeiro de 1970, 00:00 GMT, com parte fracionária.
e subtraindo os segundos correspondentes a 14 dias para obter um timestamp para o 'limit-in-seconds' na
seclim
lista ordenada de diretórios.1. Oneliner
As respostas anteriores são limpas e agradáveis, mas não preservam o
follower
diretório mais recente. A seguinte linha de comando fará isso (e pode gerenciar nomes com espaços, mas nomes com novas linhas criam problemas),testado nesta estrutura de diretórios,
igual a,
Então
follower9
é excluído porque é o diretório mais novofollower
(diretórios com nomes, que não começam comfollower
(leader1
,leader2
e2
não estão no jogo).Agora adicionamos o critério de tempo
-mtime +14
e fazemos outro 'dry run' para verificar se funciona como deveria, quando mudamos o diretório para onde existemfollower
diretórios reais,Finalmente removemos
echo
e temos uma linha de comando que pode fazer o que queremos,find
no diretório atual, diretórios com nomes começando comfollower
, que não são modificados desde 14 dias atrás.head -n -1
mais recente será excluídofollower
.xargs
como parâmetrosrm -r
para remover os diretórios que queremos remover.2. Shellscript
Eu fiz uma segunda alternativa, (o shellscript) que usa
Também tem duas opções,
-n
funcionamento a seco-v
verbosoModifiquei o shellscript de acordo com o que o OP deseja: insira o padrão como um parâmetro entre aspas simples, por exemplo, 'seguidor *'.
Sugiro que o nome do shellscript seja
prune-dirs
porque agora é mais geral (não mais apenasprune-followers
para remover diretóriosfollower*
).Recomenda-se executar o shellscript com ambas as opções na primeira vez para 'ver' o que você fará e, quando parecer correto, remova o
-n
para que o shellscript remova os diretórios antigos o suficiente para serem removidos. Então vamos chamá-loprune-dirs
e torná-lo executável.follower
subdiretóriosprune-dirs
e execute com as duas opções
-v -n
Teste
Eu testei
prune-dirs
em um diretório com os seguintes subdiretórios, como visto comfind
Uso
Executar com
-v -n
(uma execução a seco detalhada)Um teste detalhado com um padrão mais geral
Executar sem nenhuma opção (um caso real removendo diretórios)
Executar com
-v
'tentar novamente'O shellscript não lista nenhum diretório 'acima' "limit-in-seconds", e não há arquivos listados para a
rm -r
linha de comando, então o trabalho já foi feito (que é o resultado correto). Mas se você executar o shellscript novamente vários dias depois, algum novo diretório pode ser encontrado 'acima' "limit-in-seconds" e ser removido.Complementando a resposta do Rowan. Você pode alterar o ponto pelo caminho para os diretórios
With
zsh
:(remove
echo
when happy)<->
any sequence of decimal digits (a short form of<1-20>
be without bound).(){code} args
: anonymous function which here stores its number of arguments in$n
.(/omm+13)
: glob qualifier/
: only select files of type directory (equivalent offind
's-type d
)m+13
: files whose age in whole days is strictly greater than 13 days, so files that are 14 days old or older (equivalent offind
's-mtime +13
).om
: order by modification time (likels -t
younger files first)Note that it's dangerous to rely on directory modification time. directories are modified when files are added, removed or renamed in them (or when they're
touch
ed). Since those directories are numbered, you may want to rely on that numbering instead, so replaceom
withnOn
(n
umericallyO
rder in reverse (capitalO
) byn
ame).To have the pattern in a variable, replace
follower<->
with$~pattern
and setpattern='follower<->'
or any other value.No momento em que eu preciso deletar arquivos ou diretórios relacionados ao tempo, eu usaria
find
.Antes de excluir qualquer coisa, você pode executar o comando algumas vezes para ver se encontra tudo o que deseja.
Se corresponder a todos os seus critérios, você pode adicionar
-exec rm -r {} +
:A razão de estarmos usando
-exec
aqui é porque-delete
não funcionará se o diretório não estiver vazio.Confira
man find
mais orientações.Algumas soluções:
1. Baseado no GNU
find
:O script deve ser invocado como:
Como está, ele lhe dará uma corrida seca. Remova
echo
na última-exec
ação para permitir que ele realmente exclua os diretórios.Será:
-mtime
abaixo) e tenha um nome que comece com o valor de${patt}
; para cada:-exec
) that the found directory is not the last one matching the name pattern, sorting in ascending version order (-V
) (to have, for instance,follower100
placed afterfollower2
); if the test ([
) fails,find
skips to the next cycle and does not perform the actions that follow;-exec
).Here I am assuming an equivalence between sorting your directories in lexicographical order by name and sorting them by modification date. This is ok if your latest directory is defined in terms of its name.
If, instead, your latest directory is the one with the most recent modification time, we have to replace the first
-exec ...
in the above code with this one:Where with an inner
find
we find all the directories matching the name pattern, print the list of their modification times in seconds since Epoch, cut the fractional part away, sort, take the last one and check that it is not equal to that of the current result of the outerfind
.Note that, using this filter, if all the matching directories are older than 14 days and have all exactly the same modification time none of them is deleted.
Notes:
Limiting the search to the content of the current directory (
-maxdepth 1
) is not strictly required.You may want to tell
sort
how to order things, e.g. addingexport LC_ALL=C
at the beginning of the script (refer to this answer to 'What does "LC_ALL=C" do?' about the issues you may have when sorting, depending on your localization settings).Note that, using
-mtime +14
, files that have been modified between 14 and 15 days ago are skipped even if their modification time is technically older than 14*24 hours from now (refer toman find
for details; specifically, the description of-atime n
).It will work even when names contain spaces, newlines, uncommon and non-printable characters.
Compatibility: the flip side is that it is not portable: some features used here, notably
find
's-maxdepth
,-print0
and-printf
, thestat
command, the-V
option tosort
and the-z
option tosort
andtail
(and I am possibly forgetting some more), are not specified in POSIX.2. Based on shell features
This script, too, is meant to be invoked as
Again, it will give you a dry run until you remove
echo
fromecho rm -rf -- "${dirs[$i]}"
.It will:
Notes:
It will target directories older then 14 days from now (unlike
find
). Thus, these two solutions are not strictly equivalent.Also, if all the matching directories are older than the threshold and have all the same modification time, it will delete all but one of them - randomly chosen.
Names with uncommon characters are ok, including newlines and non printable ones.
Compatibility: even this solution relies on some non POSIX features: namely,
stat
and the%s
date
format. Ah, and arrays, apparently...