删除目录中超过 7 天的文件,但始终保留至少 20 个文件

删除目录中超过 7 天的文件,但始终保留至少 20 个文件

新手:我想将图片同步到文件夹,但希望它们是最近的。这就是为什么我希望如果它们超过 7 天,就删除它们。

当前代码:

find ./recentpicturesdirectory -mtime -7 -type f -delete 

现在我需要一个例外,因为文件夹中至少应该有 20 张图片。

我做了一些研究,但还是没搞明白。也许可以使用 find 命令以外的其他命令?

第一次悲伤的尝试(告诉你我是初学者)

SIZE=find recentpictesfolder -type f | wc -l

find ./recentpicturesdirectory -mtime -7 -type f \(-iname ".*" ! **if files part of -> .. i dont know ...**$SIZE ) -delete 

答案1

mtime因此,我们想要获取7 天前且不在最新 20 个文件范围内的(常规)文件。

一种方法是构建一个文件列表,其中包含修改时间和指示文件是否修改的标志mtime +7。然后,我们可以按 排序列表mtime,并取出除了最近的 20 个1之外的所有文件。最后,遍历结果列表并仅删除那些符合年龄阈值的文件:

find ./recentpicturesdirectory -type f \( -mtime +7 -printf 'Y\t' -o -printf 'N\t' \) -printf '%A@\t%p\0' |
  sort -zk2,2 | head -zn -20 | while read -r -d '' flag _ file; do \
    case "$flag" in 
      'Y') echo rm "$file" 
           ;; 
        *) echo "skipping $file (too new)"
           ;; 
    esac
  done

通过使用\0终止并将-z标志添加到sortand head(或tail)命令,我们可以处理任何合法的文件名而不会被空格阻塞。

echo 添加此文件是为了测试目的;一旦您确定已选择删除所需文件,请将其删除

1如果我们按修改时间升序排序(即从旧到新),我们可以使用head -n -20选择除最后 20 个之外的所有内容;或者,我们可以按修改时间降序排序(从新到旧),并使用tail -n +21


如果你有zsh,那么你可以用 glob 限定符来完成所有操作,我认为:

rm ./recentpicturesdirectory/**/*(.^om[1,20]^m+7)

在哪里

  • **/*递归匹配(相当于 bash globstar
  • (.) 仅匹配常规文件
  • om[1,20]按修改时间升序排列结果,选择前 20 条
  • m+7仅匹配mtime> 7 天的文件
  • ^反转接下来的所有内容

所以逻辑是

regular files NOT (in 20 most recent by mtime OR NOT mtime +7 days)

根据德摩根规则,这相当于

regular files (NOT in 20 most recent by mtime) AND (mtime +7 days)

请先进行试运行,例如

print -rl ./recentpicturesdirectory/**/*(.^om[1,20]^m+7)

答案2

这是一个执行此操作的简单脚本:

#!/bin/bash

IMGSPATH="/path/to/somewhere"

# count of all files within your directory
count=$(find $IMGSPATH -type f | wc -l)

# remove the ones older than of 7 days
while [ "$count" -gt "20" ]
do 
 find $IMGSPATH -type f -mtime +7 -print -delete -quit
 count=$((--count))
done
  1. 首先,我们计算所需目录中的所有文件。
  2. 当该目录中的文件数量大于“20”时,执行以下操作:
    • 查找第一个早于“7”天的文件。
    • 去掉它
    • 减少可用文件的数量
    • 再次执行“#2”...

测试一下:

mkdir /tmp/lab
cd /lab
touch {1..40}
touch -d "10 days ago" {1..20}

保存脚本并运行,现在/tmp/lab应该删除文件 1 到 20,运行:

touch -d "10 days ago" {21..35}

再次运行脚本,不会删除任何内容,因为无论文件是否旧,您都没有超过 20 个文件。

答案3

我的基本方法与steeldriver 的回答但我打算把它说得更简单一些。以下命令将打印一个文件列表,其中recentpicturesdirectory省略retain_count最年轻的文件 (20) 和所有小于retain_younger_days天数的文件 (7)。

find recentpicturesdirectory -type f -printf '%T@ %p\0' |
sort --zero-terminated --reverse --numeric-sort --field-separator=' ' --key 1,1 |
gawk -F ' ' -v RS='\0' -v ORS='\0' -v retain_count=20 -v retain_younger_days=7 \
  'BEGIN{ maxage = systime() - retain_younger_days * 24 * 3600; }
  (NR > retain_count) && (int($1) < maxage) { print(substr($0, length($1) + 2)); }'

由于输出以空字符终止,您可能需要通过管道将tr '\0' '\n'其显示为人类可读的。

解释

  • find recentpicturesdirectory -type f -printf '%T@ %p\0'

    recentpicturesdirectory选择其中为常规文件的(嵌套)条目( -type -f)并打印其最后修改时间和以空字符终止的路径(-printf '%T@ %p\0')。

  • sort --zero-terminated --reverse --numeric-sort --field-separator=' ' --key 1,1

    根据第一个字段 ( / )对以空字符 ( -z/ ) 终止的记录进行排序,并将空格字符字段分隔符 ( / ) 解释为十进制数 ( / ),并按降序排列 ( / )。--zero-terminated-k--key 1,1-t--field-separator=' '-n--numeric-sort-r--reverse

  • gawk -F ' ' -v RS='\0' -v ORS='\0' -v retain_count=20 -v retain_younger_days=7

    运行 GNU AWK 程序,其中空格字符字段分隔符(-F ' ')、空字符输入和输出记录分隔符(-v RS='\0' -v ORS='\0')以及变量retain_countretain_younger_days分别设置为 20 和 7。

  • BEGIN{ maxage = systime() - retain_younger_days * 24 * 3600; }

    在程序开始时将当前系统时间(以秒为单位)减去从天转换为秒maxage的值。retain_younger_days

  • (NR > retain_count) && (int($1) < maxage)

    选择上面的记录号retain_count和下面第一列中的值maxage

  • print(substr($0, length($1) + 2))

    打印当前记录省略第一个字段和后续字段分隔符,即修改时间后的路径名。

如何删除打印的文件

如果您确认要删除列出的文件,您可以通过管道将列表发送至:

xargs -r0 -- rm --

答案4

今天我正在寻找此问题的解决方案,发现此帖子和其他类似帖子中提供的解决方案要么很复杂,要么很简单,但都没有达到预期效果。我想出了以下方法。

ls -1t ${path} | tail -n +21 | xargs -I{} find {} -type f -mtime +7 | xargs -d '\n' -r rm -f

解释

  • ls -1t ${path}

    这将列出与路径匹配的文件,每行一个文件,并按修改时间排序,最新的在前。

    ${path} 是文件的路径,但应该与您想要的特定文件匹配。如果您需要更高级的模式匹配,您可以连接到 egrep 之类的程序并使用 RegEx 来匹配您想要包含的文件。

    例如,我用于网站备份的路径是类似 /backups/*_web_site_1_backup.tgz 的路径,以确保只输出那些备份文件。

    如果您有多个文件需要像这样修剪,那么我建议对所有路径使用 for 循环。否则,保留的最新文件数 x 将是不同文件的混合,而不是每个文件的最新文件数 x。

  • tail -n +21

    这将从您指定的行号开始输出上一个命令的结果。因此,如果您想保留前 20 个文件,则指定的数字应该是 21,以便从第 21 个开始输出文件名。

  • xargs -I{} find {} -type f -mtime +7

    使用 xargs 命令是因为 find 不会通过管道接受路径。通常 xargs 将管道传输的内容放在命令末尾,但 find 要求将搜索路径作为其第一个参数。-I 开关允许您指定一个字符串来标识您希望将管道传输的内容放在命令中的位置。

    -mtime +7 指定匹配超过 7 天的任何内容。由于排除了前 20 天,因此它只会匹配从 21 日开始的文件。

  • xargs -d '\n' -r rm -f

    这将删除与 find 命令匹配的文件。

    -d 开关后跟 \n 告诉 xargs 使用新行作为分隔符,这样它将尽可能多的结果传递给命令,而不是为每个文件运行命令。

    -r 开关告诉 xargs 如果没有数据则不要运行该命令。

这是一个使用 for 循环的示例。

for file_to_check in /backups/*_web_site_1_backup.tgz /backups/*_web_site_2_backup.tgz
 do
     ls -1t ${file_to_check} | tail -n +21 | xargs -I{} find {} -type f -mtime +7 | xargs -d '\n' -r rm -f
done

相关内容