需要帮助从 unix 目录中删除超过 90 天的文件,但需要保留属于月底日期的文件。 (例如:2022年2月28日、3月31日、4月30日)例如:
我的目录中有文件: /usr/home :
- ABC.txt.20220529 2022-05-30
- ABC.txt.20220530 2022-05-31
- ABC.txt.20220531 2022-06-01
- ABC.txt.20220601 2022-06-02
如果我在 6 月 1 日起的第 91 天运行我的脚本,它应该删除 1 并且不应该删除 2/3/4 需要 shell 脚本或 python 中的脚本。
答案1
假设这是您要考虑的文件名末尾的日期(20220531
in 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+89
90 天或更早的文件。
答案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 '|' -
)
因此,使用 GNUdate
和awk
支持 NUL 作为R
ecordS
分隔符的实现:
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
我喜欢其他答案,但我有一个更简单的解决方案。另外,最初的问题假设最后一个月(日期)文件始终存在。但我们都知道,您并不总是拥有本月最后一天的快照。
我正在稍微修改一下问题并回答这个问题;
- 保留每个月的最后一个文件,不一定是 31 日、30 日、28 日
- 保留 0-90 天前的文件
- 删除超过 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