Mantendo o número de arquivos na pasta constante, excluindo arquivos antigos

4

Estou tentando criar um script e executá-lo no crontab a cada 5 min, para que o número de arquivos em uma pasta sempre permaneça 50000. Se houver mais, quero que o script exclua os arquivos antigos.

#!/bin/bash
LIMIT=500000
NO=0
#Get the number of files, that has '*.pcap' in its name, with last modified time 5 days     ago

NUMBER=$(find /mnt/md0/capture/DCN/ -maxdepth 1 -name "*.pcap" |wc -l)
if [[ $NUMBER -gt $LIMIT ]]  #if number greater than limit
 then
  del=$(($NUMBER-$LIMIT))
   if [ "$del" -lt "$NO" ]
    then
     del=$(($del*-1))
   fi
   echo $del
   FILES=$(
     find /mnt/md0/capture/DCN/ -maxdepth 1 -type f -name "*.pcap" -print0 |
       xargs -0 ls -lt |
       tail -$del |
       awk '{print $8}'
   )
  rm -f ${FILES[@]}
  #delete the originals

 fi

Realmente não funciona, não é executado porque o número de arquivos é muito grande. Existe algum outro método para fazer isso?

    
por Jishnu U Nair 31.01.2014 / 09:09

4 respostas

2

eu corri o comando:

find /mnt/md0/capture/DCN/ -maxdepth 1 -type f -name "*.pcap" -print0 |
  xargs -0 ls -lt | tail -n "$del" | awk '{print $8}'

O problema que observei foi que awk '{print $8}' imprime a hora, não o nome do arquivo. awk '{print $9}' resolveria isso.

Outro problema é que xargs pode executar ls -lt várias vezes, o que daria a você várias listas ordenadas de arquivos, uma após a outra, mas a lista inteira não seria classificada.

Mas, parece haver outras simplificações que alguém poderia fazer. Você pode obter os arquivos mais antigos com:

ls -dt /mnt/md0/capture/DCN/*.pcap | tail -n "$del"

Isso pressupõe, como sua postagem parecia, que os nomes dos arquivos não têm espaços, tabulações ou caracteres de nova linha neles.

Portanto, o comando completo para excluir os arquivos $del mais antigos poderia ser:

ls -dt /mnt/md0/capture/DCN/*.pcap | tail -n "$del" | xargs rm

MORE: Se os nomes dos seus arquivos contiverem espaços, tabulações, barras invertidas ou citações neles (mas não newlines), use (assumindo o GNU ls 4.0 ( 1998) ou mais recente):

ls -dt --quoting-style=shell-always /mnt/md0/capture/DCN/*.pcap |
  tail -n "$del" | xargs rm
    
por 31.01.2014 / 09:21
5

Para aqueles que não querem fazer suposições sobre os nomes dos arquivos:

com zsh :

#! /bin/zsh -
keep=5000
rm -f /mnt/md0/capture/DCN/*.pcap(D.om[$((keep+1)),-1])

Usando os qualificadores zsh globbing:

  • D : inclui arquivos ocultos ( D ot files).
  • . : somente arquivos regulares (como find 's -type f )
  • om : inverte o rder na idade (com base no m tempo de odificação)
  • [$((keep+1)),-1] : inclua apenas o 5001 st até o último.

(pode falhar se a lista de arquivos a serem removidos for muito grande, caso em que você poderá usar zargs para dividi-lo ou ativar% built_ zsh with rm ).

Com versões relativamente recentes de ferramentas GNU:

cd /mnt/md0/capture/DCN/ &&
  find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p
cd /mnt/md0/capture/DCN/ &&
  find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p
shopt -s dotglob
cd /mnt/md0/capture/DCN/ &&
  eval "files=($(ls -dt --quoting-style=shell-always -- *.pcap))" &&
  rm -f -- "${files[@]:$keep}"
' | tr '
cd /mnt/md0/capture/DCN/ &&
  ls -dt ./.pcap ./.*.pcap ./*.pcap | awk -v keep="$keep" '
    function process() {
      if (++n > keep) {
        gsub(/[ \t\n"\'\'']/,"\\&", file)
        print file
        file = ""
      }
    }
    /\// {
      if (NR > 1) process()
      file=$0
      next
    }
    {file = file "\n" $0}
    END {if (NR > 0) process()}' | xargs rm -f
\n' '\n
#! /bin/zsh -
keep=5000
rm -f /mnt/md0/capture/DCN/*.pcap(D.om[$((keep+1)),-1])
' | sort -rn | tail -n "+$(($keep+1))" | cut -d @ -f2- | tr '
cd /mnt/md0/capture/DCN/ &&
  find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p
cd /mnt/md0/capture/DCN/ &&
  find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p
shopt -s dotglob
cd /mnt/md0/capture/DCN/ &&
  eval "files=($(ls -dt --quoting-style=shell-always -- *.pcap))" &&
  rm -f -- "${files[@]:$keep}"
' | tr '
cd /mnt/md0/capture/DCN/ &&
  ls -dt ./.pcap ./.*.pcap ./*.pcap | awk -v keep="$keep" '
    function process() {
      if (++n > keep) {
        gsub(/[ \t\n"\'\'']/,"\\&", file)
        print file
        file = ""
      }
    }
    /\// {
      if (NR > 1) process()
      file=$0
      next
    }
    {file = file "\n" $0}
    END {if (NR > 0) process()}' | xargs rm -f
\n' '\n%pre%' | sort -rn | tail -n "+$(($keep+1))" | cut -d @ -f2- | tr '%pre%\n' '\n%pre%' | xargs -r0 rm -f
' | sort -zrn | sed -z "s/[^@]*@//;1,$keep d" | xargs -r0 rm -f
\n' '\n%pre%' | xargs -r0 rm -f
' | sort -zrn | sed -z "s/[^@]*@//;1,$keep d" | xargs -r0 rm -f

(assumindo o GNU sed 4.2.2 ou acima (2012) para zmodload zsh/files , GNU -z 1.14 ou acima (1996) para sort )

-z cria uma lista delimitada por NUL de nomes de arquivos com um registro de data e hora Unix prefixado (como find ) que é classificado por 1390682991.0859627500@./file . sort remove o registro de data e hora e imprime apenas a partir do registro 5001 st . Isso é passado como argumentos para sed usando rm .

ou (com qualquer versão das ferramentas GNU):

%pre%

O mesmo, exceto que estamos usando xargs -r0 para remover o registro de data e hora e cut para selecionar as linhas a partir de 5001. Como o GNU tail e cut não suportam tail para trabalhar Registros delimitados por NUL, usamos -z para trocar os caracteres de nova linha e NUL antes e depois de fornecer os dados para eles.

Com o GNU tr (4.0 (1998) ou superior) e ls :

%pre%

(que também pode falhar se a lista de arquivos for grande. Observe também que pode incluir arquivos pcap não regulares (sem bash )).

Standard / POSIXly / portably, isso é muito mais complicado:

%pre%

(mais uma vez, você pode atingir o limite do número de argumentos e não verificar arquivos regulares).

O problema é o de lidar com os nomes de arquivos com caracteres de nova linha. Acima, estamos passando -type f para ./* , o que significa que ls será incluído uma vez para cada nome de arquivo, e usamos isso em / para identificar em qual linha cada nome de arquivo é iniciado, sabemos qual caractere de nova linha (além de todos os outros especiais para awk ) para escapar por xargs .

    
por 31.01.2014 / 09:18
1

Supondo que nenhum dos nomes de arquivo contenha espaço, tabulação, nova linha, aspas simples, aspas duplas ou caracteres de barra invertida, isso exclui os arquivos mais antigos acima do limite

mkdir t && cd t

# 50500 files, 500 to delete
touch {000001..050500}

limit=50000

ls -t|tail -n "+$(($limit + 1))"|xargs rm 

ls|wc -l
50000

tail -n +50001 mostra arquivos acima do limite.

    
por 31.01.2014 / 09:21
0

Use apenas ls com a classificação decrescente -t :

limit=5000
Cnt=0
for line in 'ls -t'
do
  if [[ $Cnt -gt $limit ]]
  then
    rm $line
  fi
  Cnt='expr $Cnt + 1'
done
    
por 31.01.2014 / 09:24