bash - 仅通过文件名识别早于 x 个月的文件并删除它们
问题描述
我有 4 个具有不同 fileName.date 格式的不同文件,其中嵌入了一个日期作为名称的一部分。我只想根据名称来识别超过 3 个月的文件,因为这些文件稍后也会被编辑/更改。我想创建一个 shell 脚本并将其作为 cron 运行。下面是同一目录下的文件:
- fileone.log.2018-03-23
- file_two_2018-03-23.log
- 文件三.log.2018-03-23
- file_four_file_four_2018-03-23.log
我已经检查了现有的例子,但没有找到我真正想要的!
解决方案
在您的意思是 90 天的前提下工作 - 如果您需要特别的月份,我们也可以检查,但这是不同的逻辑。
这是您可以使用的一些代码-
(你说你不想从列表中工作,所以我编辑使用当前目录。)
$: cat chkDates
# while read f # replaced with -
for f in *[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]*
do # first get the epoch timestamp of the file based on the sate string embedded in the name
filedate=$(
date +%s -d $(
echo $f | sed -E 's/.*([0-9]{4}-[0-9]{2}-[0-9]{2}).*/\1/'
) # this returns the date substring
) # this converts it to an epoch integer of seconds since 1/1/70
# now see if it's > 90 days ( you said 3 months. if you need *months* we have to do some more...)
daysOld=$(( ( $(date +%s) - $filedate ) / 86400 )) # this should give you an integer result, btw
if (( 90 < $daysOld ))
then echo $f is old
else echo $f is not
fi
done # < listOfFileNames # not reading list now
您可以传递date
一个日期来报告,并传递一个格式来呈现它。
sed模式解释
注意sed -E 's/.*([0-9]{4}-[0-9]{2}-[0-9]{2}).*/\1/'
命令。这假设日期格式将是一致YYYY-MM-DD
的,并且不验证合理性。它将愉快地接受任何 4 位数字,然后是 2,然后是 2,用破折号分隔。
-E
使用扩展的正则表达式,因此括号()
可以表示要记住的值,而不需要\
's. .
表示任何字符,并且*
表示前一个模式的任何数字(包括零),因此.*
表示零个或多个字符,吃掉日期之前的所有行。[0-9]
表示任何数字。{x,y}
设置连续匹配的最小(x)和最大(y)数量 - 只有一个值{4}
意味着只有前一个模式的 4 个可以做到。因此,'.*([0-9]{4}-[0-9]{2}-[0-9]{2}).*'
意味着忽略尽可能多的字符,直到看到 4 位数字,然后是破折号,2 位数字,然后是破折号,然后是 2 位数字;记住那个模式(()
's),然后忽略它后面的任何字符。
在替换中,\1
表示第一个记住的匹配,所以
sed -E 's/.*([0-9]{4}-[0-9]{2}-[0-9]{2}).*/\1/'
意味着查找并记住文件名中的日期模式,并用输出中的那部分替换整个名称。这假设日期将存在 - 在没有日期的文件名上,模式将不匹配,并且将返回整个文件名,所以要小心。
(希望有帮助。)
通过使用(您的示例是格式一致的,所以我使用它)将日期字符串与文件名隔离开来sed
,我们将其传入并使用 , 请求该日期字符串的 UNIX Epoch 时间戳date +%s -d $(...)
,以用数学方便的数字表示文件。
从相同格式的当前日期中减去它,您将获得文件的大致年龄(以秒为单位)。将它除以一天中的秒数,你就得到了几天的时间。文件日期将默认为午夜,但数学会删除分数,所以它会整理出来。
这是我根据您的示例制作的文件列表
$: cat listOfFileNames
fileone.log.2018-03-23
fileone.log.2018-09-23
file_two_2018-03-23.log
file_two_2018-08-23.log
filethree.log.2018-03-23
filethree.log.2018-10-02
file_four_file_four_2018-03-23.log
file_four_file_four_2019-03-23.log
我为每个文件添加了一个文件,该文件将在发布后的 90 天内 - 包括一个“过期”的文件,这种情况很容易发生。
这是输出。
$: ./chkDates
fileone.log.2018-03-23 is old
fileone.log.2018-09-23 is not
file_two_2018-03-23.log is old
file_two_2018-08-23.log is not
filethree.log.2018-03-23 is old
filethree.log.2018-10-02 is not
file_four_file_four_2018-03-23.log is old
file_four_file_four_2019-03-23.log is not
这就是你的想法?
仅获取日期字符串的另一种纯 bash 方法
(您仍然需要date
转换为纪元秒...)
代替
filedate=$(
date +%s -d $(
echo $f | sed -E 's/.*([0-9]{4}-[0-9]{2}-[0-9]{2}).*/\1/'
) # this returns the date substring
) # this converts it to an epoch integer of seconds since 1/1/70
这似乎不适合你,试试这个:
tmp=${f%[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]*} # unwanted prefix
d=${f#$tmp} # prefix removed
tmp=${f#*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]} # unwanted suffix
filedate=${d%$tmp} # suffix removed
filedate=$( date +%s --date=$filedate ) # epoch time
这很难阅读,但不必产生尽可能多的子流程来完成工作。:)
如果这不起作用,那么我怀疑你的date
. 矿:
$: date --version
date (GNU coreutils) 8.26
推荐阅读
- firebase - 错误:来自 google.com 的 OAuth 响应无效
- laravel - 如何强制 laravel 在我的翻译文件夹中使用 en.json 文件?
- python - python request.post,向服务器发布用户评论
- python-3.x - 如何从python3中的同级目录导入?
- animation - Windows 合成 API 是否支持 2.5D 投影旋转?
- c# - 状态/会话管理 - 与 WPF 的统一
- android - Kotlin 关于将 lambda 作为属性传递
- javascript - 如何在 App 启动时使用 redux 开始获取?
- java - 如何创建一个循环来实现递归二进制搜索以搜索数组中的 n 个数字?JAVA
- r - 无法在 Shiny 应用程序中运行 RSelenium rsDriver