web-dev-qa-db-ja.com

古いファイルを削除して、フォルダ内のファイル数を一定に保つ

スクリプトを作成して5分ごとにcrontabで実行しようとしているので、フォルダー内のファイルの数は常に50000のままです。それ以上ある場合は、スクリプトで古いファイルを削除します。

#!/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

ファイルの数が多すぎるため、実際には機能しません。実行されません。これを行う他の方法はありますか?

4
Jishnu U Nair

コマンドを実行しました:

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

私が観察した問題は、awk '{print $8}'がファイル名ではなく、時刻を出力することでした。 awk '{print $9}'はそれを解決します。

もう1つの問題は、xargsls -ltを数回実行する可能性があることです。これにより、並べ替えられたファイルのリストが次々に表示されますが、リスト全体が並べ替えられません。

しかし、他にも単純化できるようです。次の方法で最も古いファイルを取得できます。

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

これは、あなたの投稿がそうであるように、ファイル名にスペース、タブ、または改行文字が含まれていないことを前提としています。

したがって、最も古い$delファイルを削除するための完全なコマンドは次のようになります。

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

MORE:ファイル名にスペース、タブ、バックスラッシュ、または引用符が含まれている可能性がある場合(ただし、not改行)、 (GNU ls 4.0(1998)以降を想定):

ls -dt --quoting-style=Shell-always /mnt/md0/capture/DCN/*.pcap |
  tail -n "$del" | xargs rm
3
John1024

ファイルの名前を推測したくない人のために:

zshの場合:

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

zshグロブ修飾子を使用しています。

  • D:隠しファイルを含む(Dotファイル)。
  • .:通常のファイルのみ(find-type fなど)
  • om:リバース o年齢に基づいて(に基づいて m改造時間)
  • [$((keep+1)),-1]:5001のみを含めるst 最後まで。

(削除するファイルのリストが非常に大きい場合は失敗する可能性があります。その場合は、zargsを使用して分割するか、zshの組み込みrmzmodload zsh/filesで有効にすることができます。 )。

GNUツールの比較的最近のバージョンでは:

cd /mnt/md0/capture/DCN/ &&
  find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p\0' |
    sort -zrn | sed -z "s/[^@]*@//;1,$keep d" | xargs -r0 rm -f

-zの場合はGNU sed 4.2.2以上(2012)、-zの場合はGNU sort 1.14以上(1996))と仮定)

findは、Unixタイムスタンプが先頭に付いた(1390682991.0859627500@./fileなどの)ファイル名のNUL区切りリストを作成し、sortでソートします。 sedはタイムスタンプを削除し、5001からのみ出力しますst 記録。これは、xargs -r0を使用して引数としてrmに渡されます。

または(任意のバージョンのGNUツール):

cd /mnt/md0/capture/DCN/ &&
  find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p\0' |
    tr '\0\n' '\n\0' | sort -rn | tail -n "+$(($keep+1))" |
    cut -d @ -f2- | tr  '\0\n' '\n\0' | xargs -r0 rm -f

タイムスタンプを削除するためにcutを使用し、5001から始まる行を選択するためにtailを使用していることを除いて、同じです。GNU cuttailは、NULで区切られたレコードを処理するための-zをサポートしていません。データをフィードする前後に、trを使用して改行文字とNUL文字を交換します。

GNU ls(4.0(1998)以降)、およびbashの場合:

shopt -s dotglob
cd /mnt/md0/capture/DCN/ &&
  eval "files=($(ls -dt --quoting-style=Shell-always -- *.pcap))" &&
  rm -f -- "${files[@]:$keep}"

(ファイルのリストが大きい場合にも失敗する可能性があります。また、非正規のpcapファイル(-type fなし)が含まれる場合があることに注意してください)。

標準的に/ POSIXly /ポータブルに、それは非常にトリッキーです:

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

(ここでも、引数の数の制限に達する可能性があり、通常のファイルをチェックしません)。

トリッキーな点は、ファイル名を改行文字で処理することです。上記では、./*lsに渡します。これは、/がファイル名ごとに1回含まれることを意味し、awkでそれを使用して、各ファイル名がどの行から始まるかを識別します。 (xargsに特別な他のすべての文字に加えて)xargsのためにエスケープするnewline文字。

5

どのファイル名にもスペース、タブ、改行、一重引用符、二重引用符、または円記号が含まれていないと仮定すると、これにより、制限を超える最も古いファイルが削除されます。

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は制限を超えるファイルを表示します。

1
user55518

降順の並べ替えでlsを使用するだけです-t

limit=5000
Cnt=0
for line in `ls -t`
do
  if [[ $Cnt -gt $limit ]]
  then
    rm $line
  fi
  Cnt=`expr $Cnt + 1`
done
0
Tik0