使用Linux Bash脚本清理存档文件

3

这是我的问题,

我有一个文件夹,其中存储着多个具有特定格式的文件:

Name_of_file.TypeMM-DD-YYYY-HH:MM

其中MM-DD-YYYY-HH:MM是其创建时间。可能会有多个具有相同名称但不同时间的文件。

我想要一个脚本,可以保留每个文件的最新3个版本。

所以,我在这里找到了一个例子:删除旧文件的shell脚本

但我不想删除一些文件,而是保留一定数量的较新文件。有没有办法获取该find命令,解析Name_of_file并保留最新的3个文件???

这是我尝试过的代码,但它并不完全符合我的需求。

find /the/folder -type f -name 'Name_of_file.Type*' -mtime +3 -delete

感谢您的帮助!


我决定提供我的最终解决方案,以便有需要的人获取。这是两种解决方案的结合。

ls -r | grep -P "(.+)\d{4}-\d{2}-\d{2}-\d{2}:\d{2}" | awk 'NR > 3' | xargs rm

一行命令,高效便捷。如果日期或名称的模式发生变化,只需更改grep -P匹配模式即可。这样,您可以确保只有符合此模式的文件将被删除。


1
文件格式是固定的还是可以更改的?按照“YYYY-MM-DD-HH:MM”排序比“MM-DD-YYYY-HH:MM”容易得多。 - Shawn Chin
是的,我可以更改它。实际上这很容易。 - Franko
你打算使用文件名来确定最新的3个文件吗? - Franko
我以为那就是问题所在。你想要使用实际的修改时间吗? - Shawn Chin
我并不真的在意,只要我能达到我的目标就好 :D - Franko
3个回答

1
假设我们使用文件名中的日期对存档文件进行日期标记,并且可以将日期格式更改为YYYY-MM-DD-HH:MM(如上面的评论所建立的),这里有一个快速而简单的Shell脚本,以保持当前工作目录中每个文件的最新3个版本:
#!/bin/bash
KEEP=3  # number of versions to keep

while read FNAME; do
    NODATE=${FNAME:0:-16}  # get filename without the date (remove last 16 chars)
    if [ "$NODATE" != "$LASTSEEN" ]; then  # new file found
        FOUND=1; LASTSEEN="$NODATE"
    else  # same file, different date
        let FOUND="FOUND + 1"
        if [ $FOUND -gt $KEEP ]; then
            echo "- Deleting older file: $FNAME"
            rm "$FNAME"
        fi
    fi
done < <(\ls -r | grep -P "(.+)\d{4}-\d{2}-\d{2}-\d{2}:\d{2}")

示例运行:

[me@home]$ ls
another_file.txt2011-02-11-08:05  
another_file.txt2012-12-09-23:13  
delete_old.sh
not_an_archive.jpg 
some_file.exe2011-12-12-12:11             
some_file.exe2012-01-11-23:11 
some_file.exe2012-12-10-00:11  
some_file.exe2013-03-01-23:11  
some_file.exe2013-03-01-23:12

[me@home]$ ./delete_old.sh 
- Deleting older file: some_file.exe2012-01-11-23:11
- Deleting older file: some_file.exe2011-12-12-12:11

[me@home]$ ls
another_file.txt2011-02-11-08:05
another_file.txt2012-12-09-23:13
delete_old.sh
not_an_archive.jpg
some_file.exe2012-12-10-00:11
some_file.exe2013-03-01-23:11
some_file.exe2013-03-01-23:12

基本上,只需将文件名更改为日期形式YYYY-MM-DD-HH:MM,普通的字符串排序(例如由ls执行的排序)将自动按日期时间排序将相似的文件组合在一起。
最后一行的ls -r仅列出当前工作目录中的所有文件,并以相反的顺序打印结果,以便新的归档文件首先出现。
我们通过grep传递输出以提取仅符合正确格式的文件。
然后循环该命令组合的输出(请参见while循环),并且在同一文件名的3个出现之后(减去日期部分),我们可以简单地开始删除。

当我尝试运行脚本的时候,出现了以下错误:在第15行处:`done <(\ls -r | grep -P "(.+)\d{4}-\d{2}-\d{2}-\d{2}:\d{2}")' - Franko
什么是错误信息?你好像缺少一个 < 符号。应该是 done < <(....) - Shawn Chin

1
请问您能不能确保文件的时间戳和文件名上的时间戳完全一致?如果它们有一点偏差,您在意吗? ls命令可以按照时间戳顺序对文件进行排序。您可以像这样执行某些操作
$ ls -t | awk 'NR > 3' | xargs rm
  • ls -t 命令按照修改时间列出文件,最新的排在前面。
  • awk 'NR > 3' 命令打印出文件列表,除了前三行(即最新的三个文件)
  • xargs rm 命令将删除早于前三个文件的文件。

现在,这不是完美的解决方案。使用 xargs 可能会出现问题,因为文件名可能包含奇怪的字符或空格。如果你可以保证这种情况不会发生,那么这应该没问题。

另外,你可能想要按名称分组文件,并保留最后三个文件。嗯...

ls | sed 's/MM-DD-YYYY-HH:MM*$//' | sort -u | while read file
do
    ls -t $file* | awk 'NR > 3' | xargs rm
done
ls命令将列出目录中的所有文件。`sed 's/\MM-DD-YYYY-HH:MM//'` 将从文件中删除日期时间戳。`sort -u` 确保您只拥有唯一的文件名。因此,
file1.txt-01-12-1950
file2.txt-02-12-1978
file2.txt-03-12-1991

将被简化为:

只会被减少到:

file1.txt
file2.txt

这些被放置在循环中,ls $file* 将列出以文件名和后缀开头的所有文件,但会将其导入 awk,它将剥离最新的三个,然后将其导入 xargs rm,它将删除除最新的三个之外的所有内容。

太好了!它完美地运行了。我犯了几个错误,每个文件都没有被删除。(rm:缺少操作数,请尝试“rm --help”获取更多信息。)我会处理的,不用担心。非常感谢你! - Franko

1

这个管道会获取当前目录中修改时间最新的3个文件。

stat -c $'%Y\t%n' file* | sort -n | tail -3 | cut -f 2-

获取除了最新的3个之外的所有内容:
stat -c $'%Y\t%n' file* | sort -rn | tail -n +4 | cut -f 2-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接