需要删除超过 90 天的文件(该月最后一天除外)

需要删除超过 90 天的文件(该月最后一天除外)

需要帮助从 unix 目录中删除超过 90 天的文件,但需要保留属于月底日期的文件。 (例如:2022年2月28日、3月31日、4月30日)例如:

我的目录中有文件: /usr/home :

  1. ABC.txt.20220529 2022-05-30
  2. ABC.txt.20220530 2022-05-31
  3. ABC.txt.20220531 2022-06-01
  4. ABC.txt.20220601 2022-06-02

如果我在 6 月 1 日起的第 91 天运行我的脚本,它应该删除 1 并且不应该删除 2/3/4 需要 shell 脚本或 python 中的脚本。

答案1

假设这是您要考虑的文件名末尾的日期(20220531in ABC.txt.20220531), in zsh,您可以这样做:

#! /bin/zsh -
zmodload zsh/datetime
day=86400
strftime -s range '<19700101-%Y%m%d>' $(( EPOCHSECONDS - 91 * day ))
not_last() {
  local t
  TZ=UTC0 strftime -rs t %Y%m%d $REPLY:e &&
    TZ=UTC0 strftime -s t %d $(( t + day )) &&
    (( t != 1 ))
}
echo rm -f -- **/*.txt.$~range(-.+not_last)

如果是最后修改时间:

#! /bin/zsh -
zmodload zsh/datetime
zmodload zsh/stat
day=86400
not_last() {
  local t
  stat -A t +mtime -- $REPLY &&
    strftime -s t %d $(( t + day )) &&
    (( t != 1 ))
}
echo rm -f -- **/*.txt.*(-.m+90+not_last)

请记住,如果 DST 在该月的第一天或最后一天发生变化,则很有可能会影响第二天的计算。

考虑文件的类型和 mtime符号链接解析。如果要忽略符号链接,请删除-glob 限定符。添加D限定符以同时考虑隐藏文件。**/如果您不想考虑子目录中的文件,请删除。

echo如果对结果满意,请删除(试运行)。

请注意m+90, like find's-mtime +90选择 91 天或更早的文件,更改为m+8990 天或更早的文件。

答案2

每月的最后一天是以 0131、0331、0430...1231 和 0229 结尾的年份(双六分相年份)和 0228(其他年份)。

使用 GNUdate和支持zsh-style{x..y}大括号扩展的 shell,您可以获得 1970 年到 2099 年 2 月最后一天的列表,例如:

printf '%s\n' {1970..2099}'-03-01 -1 day' | date -uf- +%Y%m%d

因此,您可以构建一个扩展的正则表达式来匹配这些日期:

regexp=$(
  {
    printf '%s\n' {0{1,3,5,7,8},10,12}31 {04,06,09,11}30
    printf '%s\n' {1970..2099}'-03-01 -1 day' | date -uf- '+%Y%m%d'
  } | paste -sd '|' -
)

因此,使用 GNUdateawk支持 NUL 作为RecordS分隔符的实现:

LC_ALL=C find . -name '*.txt.[0-9]*' -print0 |
  LC_ALL=C awk -F. -v 'RS=\0' \
                   -v 'ORS=\0' \
                   -v regexp="($regexp)\$" \
                   -v cutoff="$(date -d '90 days ago' +%Y%m%d)" '
    /txt\.[0-9]{8}$/ && $NF < cutoff && $NF !~ regexp' |
  xargs -r0 echo rm -f

或者匹配文件的最后修改时间而不是文件名称末尾的日期,GNU 实现如下find

LC_ALL=C find . -regextype posix-extended \
                -regex '.*\.txt\.[0-9]{8}' \
                -mtime +90 \
                -printf '%TY%Tm%Td-%p\0' |
  LC_ALL=C awk -v 'RS=\0' \
               -v 'ORS=\0' \
               -v regexp="^[0-9]*($regexp)-" '
    $0 !~ regexp {print substr($0, 10)}' |
  xargs -r0 echo rm -f

您可以使用相同的方法来构造与这些匹配的 zsh glob 模式。

#! /bin/zsh -
zmodload zsh/datetime
set -o extendedglob
day=86400

start=19700101
strftime -s end %Y%m%d $(( EPOCHSECONDS - 91 * day ))
range="<$start-$end>"

list=({0{1,3,5,7,8},10,12}31 {04,06,09,11}30)

for ((y = $start[1,4]; y <= $end[1,4]; y++)) {
  TZ=UTC0 strftime -rs t %Y%m%d ${y}0301 &&
    TZ=UTC0 strftime -s d %Y%m%d $(( t - day )) &&
    list+=($d)
}
endofmonth="*(${(j[|])list})"

echo rm -f -- **/*.txt.($~range~$~endofmonth)

答案3

我喜欢其他答案,但我有一个更简单的解决方案。另外,最初的问题假设最后一个月(日期)文件始终存在。但我们都知道,您并不总是拥有本月最后一天的快照。

我正在稍微修改一下问题并回答这个问题;

  1. 保留每个月的最后一个文件,不一定是 31 日、30 日、28 日
  2. 保留 0-90 天前的文件
  3. 删除超过 90 天的文件,但如果它们是一个月内的最后一个文件,则不会删除。

我不关心示例中的文件列表,因为方法很重要。如果您了解该方法,则可以调整输入。

给定一个随机的日期列表:

function dates() { echo 2022-12-{06..12}  2022-{01,03,05}-{00..31} 2022-02-{00..28} 2022-{04,06}-{01..30}   2022-12-{01..06} 2022-10-{01..03}| tr ' ' \\n;  }

在此列表中,所有日期均出现在 1-6 月份中,12 月仅列出 12 天,10 月仅列出 3 天。

去寻找最后的日子展示在每个月的列表中,我们将按升序对列表进行排序,然后记住每个月的每个“最旧”日期。这给出了最后一个月

$ dates | sort \
  | awk -F- '{ lom[$1$2]=$1"-"$2"-"$3 } END { for (i in lom) { print lom[i]} }' \
  | tee /tmp/lom  
2022-01-31
2022-02-28
2022-03-31
2022-04-30
2022-05-31
2022-06-30
2022-10-03
2022-12-12

我不关心现实生活中 IT 问题中的日历日期。我关心实际存在的文件。如果12号是12月的最后一个快照并且没有31号,因为那天系统坏了,那么我想保留12号。

所以现在我们知道了什么不删除。另一部分已超过 90 天:

dates | awk -v cutoff=$(date +%Y-%m-%d -d 'today -90 days') \
            '{ if ($1 < cutoff) { print $1 } }'  \
      | grep -v -f /tmp/lom

这将打印超过 90 天的日期并排除最后的飞蛾条目。简短而甜蜜。完美的。

正如大师所指出的,上面的整个事情可以一行完成。哇!

dates | sort -r | awk -v cutoff=$(date +%F -d '-90 days') -F- '$0 < cutoff && seen[$1$2]++'

生成的要清除的日期列表包含以下内容:

2022-01-00  2022-03-11  2022-05-22  2022-04-05
2022-01-01  2022-03-12  2022-05-23  2022-04-06
2022-01-02  2022-03-13  2022-05-24  2022-04-07
2022-01-03  2022-03-14  2022-05-25  2022-04-08
2022-01-04  2022-03-15  2022-05-26  2022-04-09
2022-01-05  2022-03-16  2022-05-27  2022-04-10
2022-01-06  2022-03-17  2022-05-28  2022-04-11
2022-01-07  2022-03-18  2022-05-29  2022-04-12
2022-01-08  2022-03-19  2022-05-30  2022-04-13
2022-01-09  2022-03-20  2022-02-00  2022-04-14
2022-01-10  2022-03-21  2022-02-01  2022-04-15
2022-01-11  2022-03-22  2022-02-02  2022-04-16
2022-01-12  2022-03-23  2022-02-03  2022-04-17
2022-01-13  2022-03-24  2022-02-04  2022-04-18
2022-01-14  2022-03-25  2022-02-05  2022-04-19
2022-01-15  2022-03-26  2022-02-06  2022-04-20
2022-01-16  2022-03-27  2022-02-07  2022-04-21
2022-01-17  2022-03-28  2022-02-08  2022-04-22
2022-01-18  2022-03-29  2022-02-09  2022-04-23
2022-01-19  2022-03-30  2022-02-10  2022-04-24
2022-01-20  2022-05-00  2022-02-11  2022-04-25
2022-01-21  2022-05-01  2022-02-12  2022-04-26
2022-01-22  2022-05-02  2022-02-13  2022-04-27
2022-01-23  2022-05-03  2022-02-14  2022-04-28
2022-01-24  2022-05-04  2022-02-15  2022-04-29
2022-01-25  2022-05-05  2022-02-16  2022-06-00
2022-01-26  2022-05-06  2022-02-17  2022-06-01
2022-01-27  2022-05-07  2022-02-18  2022-06-02
2022-01-28  2022-05-08  2022-02-19  2022-06-03
2022-01-29  2022-05-09  2022-02-20  2022-06-04
2022-01-30  2022-05-10  2022-02-21  2022-06-05
2022-03-00  2022-05-11  2022-02-22  2022-06-06
2022-03-01  2022-05-12  2022-02-23  2022-06-07
2022-03-02  2022-05-13  2022-02-24  2022-06-08
2022-03-03  2022-05-14  2022-02-25  2022-06-09
2022-03-04  2022-05-15  2022-02-26  2022-06-10
2022-03-05  2022-05-16  2022-02-27  2022-06-11
2022-03-06  2022-05-17  2022-04-00  2022-06-12
2022-03-07  2022-05-18  2022-04-01  2022-06-13
2022-03-08  2022-05-19  2022-04-02  2022-06-14
2022-03-09  2022-05-20  2022-04-03  2022-06-15
2022-03-10  2022-05-21  2022-04-04  2022-06-16

相关内容