保留每个月的最后一个文件并删除其余的

保留每个月的最后一个文件并删除其余的

我有如下文件。我想保留 9 月 30 日、10 月 30 日......的文件并删除其余的。

-rw-r--r-- 1 nbswmcm advboprd 13463761 Sep  2 01:19 vtm_data_12month_20140902.txt
-rw-r--r-- 1 nbswmcm advboprd 13474125 Sep  3 01:51 vtm_data_12month_20140903.txt
-rw-r--r-- 1 nbswmcm advboprd 13492755 Sep  4 01:57 vtm_data_12month_20140904.txt
-rw-r--r-- 1 nbswmcm advboprd 13499981 Sep  5 01:59 vtm_data_12month_20140905.txt
-rw-r--r-- 1 nbswmcm advboprd 13507296 Sep  7 08:39 vtm_data_12month_20140907.txt
-rw-r--r-- 1 nbswmcm advboprd 13508099 Sep  9 04:02 vtm_data_12month_20140909.txt
-rw-r--r-- 1 nbswmcm advboprd 13508886 Sep 10 01:33 vtm_data_12month_20140910.txt
-rw-r--r-- 1 nbswmcm advboprd 13513056 Sep 11 02:25 vtm_data_12month_20140911.txt
-rw-r--r-- 1 nbswmcm advboprd 13512334 Sep 12 02:36 vtm_data_12month_20140912.txt
-rw-r--r-- 1 nbswmcm advboprd 13512391 Sep 14 08:41 vtm_data_12month_20140914.txt
-rw-r--r-- 1 nbswmcm advboprd 13515984 Sep 16 02:35 vtm_data_12month_20140916.txt
-rw-r--r-- 1 nbswmcm advboprd 13516946 Sep 17 02:27 vtm_data_12month_20140917.txt
-rw-r--r-- 1 nbswmcm advboprd 13523528 Sep 18 02:39 vtm_data_12month_20140918.txt
-rw-r--r-- 1 nbswmcm advboprd 13520200 Sep 19 02:28 vtm_data_12month_20140919.txt
-rw-r--r-- 1 nbswmcm advboprd 13514677 Sep 21 09:33 vtm_data_12month_20140921.txt
-rw-r--r-- 1 nbswmcm advboprd 13518239 Sep 23 02:29 vtm_data_12month_20140923.txt
-rw-r--r-- 1 nbswmcm advboprd 13488002 Sep 24 02:51 vtm_data_12month_20140924.txt
-rw-r--r-- 1 nbswmcm advboprd 13491370 Sep 25 02:38 vtm_data_12month_20140925.txt
-rw-r--r-- 1 nbswmcm advboprd 13414606 Sep 26 02:42 vtm_data_12month_20140926.txt
-rw-r--r-- 1 nbswmcm advboprd 13411621 Sep 28 08:59 vtm_data_12month_20140928.txt
-rw-r--r-- 1 nbswmcm advboprd 13529594 Sep 30 02:52 vtm_data_12month_20140930.txt
-rw-r--r-- 1 nbswmcm advboprd 13520560 Oct  1 02:54 vtm_data_12month_20141001.txt
-rw-r--r-- 1 nbswmcm advboprd 13519613 Oct  2 02:54 vtm_data_12month_20141002.txt
-rw-r--r-- 1 nbswmcm advboprd 13534704 Oct  3 02:19 vtm_data_12month_20141003.txt
-rw-r--r-- 1 nbswmcm advboprd 13545015 Oct  5 08:47 vtm_data_12month_20141005.txt
-rw-r--r-- 1 nbswmcm advboprd 13541506 Oct  7 02:51 vtm_data_12month_20141007.txt
-rw-r--r-- 1 nbswmcm advboprd 13556650 Oct  8 02:31 vtm_data_12month_20141008.txt
-rw-r--r-- 1 nbswmcm advboprd 13551903 Oct  9 02:33 vtm_data_12month_20141009.txt
-rw-r--r-- 1 nbswmcm advboprd 13567484 Oct 10 02:33 vtm_data_12month_20141010.txt
-rw-r--r-- 1 nbswmcm advboprd 13569503 Oct 12 08:40 vtm_data_12month_20141012.txt
-rw-r--r-- 1 nbswmcm advboprd 13567657 Oct 14 02:25 vtm_data_12month_20141014.txt
-rw-r--r-- 1 nbswmcm advboprd 13574132 Oct 15 02:40 vtm_data_12month_20141015.txt
-rw-r--r-- 1 nbswmcm advboprd 13581260 Oct 16 02:50 vtm_data_12month_20141016.txt
-rw-r--r-- 1 nbswmcm advboprd 13585758 Oct 17 02:27 vtm_data_12month_20141017.txt
-rw-r--r-- 1 nbswmcm advboprd 13587851 Oct 19 10:02 vtm_data_12month_20141019.txt
-rw-r--r-- 1 nbswmcm advboprd 13591515 Oct 21 02:43 vtm_data_12month_20141021.txt
-rw-r--r-- 1 nbswmcm advboprd 13602271 Oct 22 02:59 vtm_data_12month_20141022.txt
-rw-r--r-- 1 nbswmcm advboprd 13604358 Oct 23 03:22 vtm_data_12month_20141023.txt
-rw-r--r-- 1 nbswmcm advboprd 13607622 Oct 24 02:52 vtm_data_12month_20141024.txt
-rw-r--r-- 1 nbswmcm advboprd 13605666 Oct 26 10:25 vtm_data_12month_20141026.txt
-rw-r--r-- 1 nbswmcm advboprd 13612303 Oct 28 02:32 vtm_data_12month_20141028.txt
-rw-r--r-- 1 nbswmcm advboprd 13617526 Oct 29 02:49 vtm_data_12month_20141029.txt
-rw-r--r-- 1 nbswmcm advboprd 13627963 Oct 30 02:38 vtm_data_12month_20141030.txt

答案1

在 GNU 系统上,使用特定的文件名模式,

ls -r | uniq -w23

会给你保留的。所以你可以把它们移走:

ls -r | uniq -w23 | xargs mv -t ../to-keep/

并删除所有剩余文件。

23 是 的长度vtm_data_12month_201409。因此,uniq将仅返回具有相同 23 个字符长前缀的文件列表中的第一个文件(在反向排序的文件列表中)。

一次性完成:

ls -r | awk -F_ 'a[substr($NF,1,6)]++'

其中列出了要删除的文件。

ls -r | awk -F_ 'a[substr($NF,1,6)]++' | xargs rm -f

(假设文件名不包含空白、引号或反斜杠字符)。

在这里,我们不是查看前 23 个字符,而是查看最后一个_字符之后的前 6 个字符。

答案2

使用logrotate命令。这是处理/var/log.它可以根据日期或大小轮换日志。

看看/etc/cron.daily/logrotate/etc/logrotate.conf。您应该能够放入一个条目/etc/logrotate.conf来处理您想要旋转的文件。

另请参阅此网站:http://www.rackspace.com/knowledge_center/article/understanding-logrotate-utility

如果您需要更多帮助,请告诉我。我会尽力。

好的,所以我的系统/etc/cron.daily/logrotate每天都会调用 logrotate 一次。 /etc/logrotate.conf告诉我们logrotate如何处理每个文件。所以你只需要担心修改/etc/logrotate.conf

您只需将这样的条目添加到您的/etc/logrotate.conf文件中即可。

/var/log/LOGFILENAME {
    monthly
    create 0664 root root
    rotate 1
}

然后重新启动您的系统或 cron 或您所做的更改生效。您还可以通过logrotate直接调用来测试您的配置文件,因此:

/usr/sbin/logrotate /etc/logrotate.conf

该行rotate 1告诉logrotate您保留一份旧副本,这样您最终将获得两个月的日志:上个月和本月。如果您只想保留当前月份的日志,请更改rotate 1为。rotate 0

答案3

您需要普遍解决这个问题还是只解决一次?如果您只需要解决一次,有时简单的解决方案是最好的。我们可以在 Bash 中使用大括号扩展:

rm vtm_data_12month_2014{09,10}{01..29}.txt

这可能适用于您的情况,因为:

  • 我们要发送的参数数量rm不太可能超过 ARG_MAX,并且
  • 十月和九月您想要停留的日期是相同的。

如果您需要更普遍地解决此问题,则需要考虑不同月份在不同日期结束的事实(例如,10 月于 31 日结束,但您的示例仅包含截至 30 日的数据)。

如果可以依赖示例中的文件命名方案,则以下命令将删除每月可用的除最新文件之外的所有文件(基于文件名,而不是与文件创建或修改相关的实际时间戳):

get_years() {
  find ./ -type f | cut -d'_' -f4 | cut -c1-4 | sort | uniq
}

get_months_for_year() {
  year=$1
  find ./ -iname "vtm_data_12month_${year}*.txt" -type f | cut -d'_' -f4 | cut -c5-6 | sort | uniq
}

get_latest_for_year_month() {
  year=$1
  month=$2
  find ./ -iname "vtm_data_12month_${year}${month}*.txt" -type f | cut -d'_' -f4 | cut -c7-8 | sort | tail -1
}

for year in $(get_years); do
  for month in $(get_months_for_year $year); do
     latest=$(get_latest_for_year_month $year $month)
     end=$(($latest - 1))
     for i in $(seq 1 $end); do 
      day=$(printf '%02d' $i)
      rm vtm_data_12month_${year}${month}${day}.txt
     done
  done
done

除 bash 之外,具有 DateTime 库的语言可能会为您提供更简洁、更可靠的解决方案。如果某些天的文件丢失,此处提供的两种解决方案都会发出错误。

答案4

使用 bash 脚本检查日期的有效性并生成日期范围很困难且容易出错。最好的选择是使用pythonperl或任何其他可以进行深入检查的高级脚本语言。我已经更新了脚本,以便它可以删除日期范围内的文件并排除日期范围。

选项将类似于

删除范围内的文件

./dfile.py --from 20140929 --to 20141001  --range

删除范围之外的文件

./dfile.py --from 20140929 --to 20141001  --out-range

如果参数给出错误,该程序还会生成有用的帮助消息。

#!/usr/bin/env python3


import os
import sys
import argparse
import datetime

parser = argparse.ArgumentParser()
parser.add_argument('--from', dest="fromd", type=str, required=True, help="From date")
parser.add_argument('--to', dest="tod", type=str, required=True, help="To date")
parser.add_argument('--range', dest='drange', action='store_true', help="Delete files between the given date")
parser.add_argument('--out-range', dest="orange", action='store_true', help="Delete files apart form the given date")

args = parser.parse_args()

if args.drange and args.orange:
    print('Enter either --range or --out-range option')
    sys.exit(1)
elif not (args.drange or args.orange):
    print('You must select either --range or --out-range option')
    sys.exit(1)

from_date = args.fromd
to_date = args.tod
path='/tmp/tmp.54JUy4ZP6x/'


try:
    from_date = datetime.datetime.strptime(from_date, '%Y%m%d').date()
    to_date   = datetime.datetime.strptime(to_date, '%Y%m%d').date()
except ValueError:
    print('Check if the date has been given in YYYYMMDD format')
    sys.exit(1)

files = [ x for x in os.listdir(path) if x.endswith('.txt') ]


for file in files:

    file_date = datetime.datetime.strptime(file[17:25], '%Y%m%d').date()

    if args.orange:
        # Delete files out of date range
        if not from_date < file_date < to_date:
            print('Deleting file {}'.format(file))
            os.remove(path + '/' + file)
    else:
        # Delete files within date range
        if from_date < file_date < to_date:
            print('Deleting file {}'.format(file))
            os.remove(path + '/' + file)

这里所有参数都是可配置的,除了path需要在程序中更改的参数之外。

希望对您有帮助。

相关内容