Encontre o arquivo mais recente por extensão numerada

2

Eu quero limpar automaticamente os arquivos de log mais antigos primeiro em um sistema embarcado onde o relógio pode ser redefinido (para que os tempos de arquivo não sejam úteis). Eu estou procurando um script de shell simples para encontrar o arquivo mais recente, então eu sei o que não excluir. Eles seguem esta forma:

LogFileTypeA.log
LogFileTypeA.log.0
LogFileTypeA.log.1
LogFileTypeB.log     <-- this is the latest of Type B
LogFileTypeA.log.2
LogFileTypeC.log 
LogFileTypeC.log.0   <-- this is the latest of Type C
LogFileTypeA.log.3   <-- this is the latest of Type A

Eu quero excluir tudo, exceto o mais recente de cada tipo. Existe uma maneira fácil de encontrar o mais recente usando um script de shell?

Estou usando a versão Bash GNU bash, version 4.4.12(1)-release (sparc-buildroot-linux-gnu) e sort --version revela BusyBox v1.26.2 (2018-05-07 10:50:40 MDT) multi-call binary.

Aqui está um teste rápido ... se você executar isso para configurar um cenário:

#!/bin/bash
touch typeA.log
touch typeA.log.0
touch typeA.log.1
touch typeA.log.5
touch typeB.log
touch typeB.log.0
touch typeC.log
touch typeD.log.0
touch typeD.log.1
touch typeD.log.2
touch typeD.log.3
touch typeD.log.4
touch typeD.log.5
touch typeD.log.6
touch typeD.log.7
touch typeD.log.8
touch typeD.log.9
touch typeD.log.10
touch typeD.log.11
touch typeD.log.12
touch typeD.log.99
touch typeD.log.100
touch typeD.log.101
touch typeD.log.215
echo A=5
echo B=0
echo C=log
echo D=215

Depois de executar um script de solução, você deve sair:

typeA.log.5
typeB.log.0
typeC.log
typeD.log.215
    
por kmort 15.08.2018 / 17:43

2 respostas

4

Com zsh :

typeset -A seen=()
for f (*.log*(nOn)) {((seen[${f%%.*}]++)) && echo rm -f -- $f}

(remova echo se estiver satisfeito com o resultado.

*.log*(nOn) lista os arquivos *.log* numericamente ao contrário (onde f.log classifica após f.log.0 após f.log.9 depois de f.log.10 ).

typeset -A seen=() declara uma matriz associativa $seen . Nós rm do arquivo se a parte antes do primeiro . ( ${f%%.*} ) foi vista antes.

Com qualquer shell e utilitários GNU

printf '%s
printf '%s\n' *.log* |
  sort -rt. -k1,1 -k3,3rn |
  awk -F. 'seen[$1]++' |
  xargs echo rm -f --
' *.log* | sort -rzV | gawk -v RS='
typeset -A seen=()
for f (*.log*(nOn)) {((seen[${f%%.*}]++)) && echo rm -f -- $f}
' -v ORS='
printf '%s
printf '%s\n' *.log* |
  sort -rt. -k1,1 -k3,3rn |
  awk -F. 'seen[$1]++' |
  xargs echo rm -f --
' *.log* | sort -rzV | gawk -v RS='%pre%' -v ORS='%pre%' -F. 'seen[$1]++' | xargs -r0 echo rm -f --
' -F. 'seen[$1]++' | xargs -r0 echo rm -f --

POSIXly ou com utilitários do busybox

Mas, supondo que os nomes dos arquivos não contenham caracteres de espaçamento ou citações ou barras invertidas:

%pre%

Todos eles assumem a parte do nome do arquivo antes de .log não conter pontos.

    
por 15.08.2018 / 17:52
1

Parece que você deseja manter o arquivo que ordena por último na ordem de classificação lexicográfica padrão.

Bem, a ordem de classificação padrão não funciona com números que têm uma quantidade variável de dígitos. Mas se os números forem consecutivos , sem nenhum entre zero e o mais alto (como na pergunta original), podemos contar do zero até encontrarmos o número que não está lá, e remover todos, exceto o último encontrado:

#!/bin/sh
for group in *.log; do
    i=0
    last="$group"
    while [ -f "$group.$i" ]; do
        rm "$last"
        last="$group.$i"
        i=$((i+1))
    done
    echo "did not remove '$last'"
done

Após touch foo.log foo.log.{0..13} bar.log asdf.log asdf.log.0 que remove todos, exceto foo.log.13 , bar.log e asdf.log.0 .

    
por 15.08.2018 / 17:57