web-dev-qa-db-ja.com

最後のログファイルを除く古いログファイルを削除します(アルファベット順に並べ替えられます)

次の形式のログファイルがいくつかあります。

log.2014-02-19-10_24_22

つまりlog.YYYY-MM-DD-H24_MI_SS

ログファイルの名前の一部である日付は、ログファイルが最初に作成された日付です。したがって、いつでも次のログファイルをディレクトリに置くことができます。

log.2014-02-19-10_18_54
log.2014-02-19-10_21_20
log.2014-02-19-10_23_11
etc.

これで、cronjobによって呼び出され、「古い」ログファイルを削除するスクリプトができました。

$ cat delete-old-rotated-logs 
#!/usr/bin/env bash
find /home/foo -maxdepth 1 -iname log\* -type f -mmin +1800 -exec rm {} \;

私が直面している問題は、ログを記録しているプロセスがクラッシュしたため、「最新の」ログファイルもしばらくして(古いプロセスが書き込まれていないため)「古く」なり、削除されて、トレースが失われることです。 delete-old-rotated-logsスクリプトを書き直して、最後のファイル(または最後のN)以外の古いファイルを削除するにはどうすればよいですか?順序付けには、ファイル名自体または変更タイムスタンプ(より堅牢)の両方を使用できます。

find /home/foo -maxdepth 1 -iname log\* -type f -mmin +1800 |
  sort | head -n -1 | xargs rm

または、ファイル名の代わりにmtimeを使用する場合:

find /home/foo -maxdepth 1 -iname log\* -type f -mmin +1800 -exec ls -t {} + |
  tail -n +2 | xargs rm

@Stephaneのコメントから、より堅牢なアプローチは次のようになります。

IFS=$'\n'
set -f
rm $(
  find /home/foo -maxdepth 1 -iname log\* ! -name $'*\n*' -type f -mmin +1800 |
  sort | head -n -1 )

またはPOSIXシェルの場合(GNUツールが必要):

IFS='
'
ex_newline='*
*'
set -f
rm $(
  find /home/foo -maxdepth 1 -iname log\* ! -name "$ex_newline" -type f -mmin +1800 |
  sort | head -n -1 )

GNU sed/sort(およびGNU findの最近のバージョンでは、上記のすべてと同様):

find /home/foo -maxdepth 1 -iname log\* -type f -mmin +1800 -print0 |
  sort -z | sed -z '$d' | xargs -0 rm
3
Graeme

bash/ksh93/zsh

n=5        # Maximum number of files to keep
cd /home/foo || exit
files=(log.*)
((${#files[@]} <= n)) ||
  rm -f -- "${files[@]:0:${#files[@]}-n}"

zshを使用すると、次のように簡略化できます。

n=5
rm -f /home/foo/log.*(N[1,-n-1])

また、30時間以上経過したファイルのみを検討する場合は、次のようにします。

n=5
rm -f /home/foo/log.*(Nmh+30[1,-n-1])

POSIXly:

n=5
cd /home/foo || exit
set -- log.*
i=$#
while [ "$i" -gt "$n" ]; do
  set -- "$@" "$1"
  shift
  i=$(($i - 1))
done
shift "$i"
rm -f -- "$@"
2