现在是 2019 年 8 月 14 日,有一个包含日期列表 (dd.mm.yyyy) 的文本文件:
30.07.2018
14.08.2019
18.08.2019
20.08.2019
01.01.2020
列表中的日期是截止日期。
输出应如下所示:早于当前日期的日期和将在 10 天后到期的日期的列表(如果在 1 到 10 天后到期,则会列出,如果今天到期,也会列出。如果是11 天或更长时间后到期,则不列出)。
答案1
使用 GNU date
:
#! /bin/sh -
printf '%s days\n' -1 +10 |
date -f - +%d.%m.%YT |
sort -nt. -k3 -k2 -k1 -- - "$@" |
sed '/T/,/T/!d;/T/d'
我们的想法是对列表进行排序,其中我们插入了昨天和 10 天后的日期,以 结尾T
,例如如果在 2019-08-14 运行,我们会得到:
30.07.2018
13.08.2019T
14.08.2019
18.08.2019
20.08.2019
24.08.2019T
01.01.2020
我们提取这两行之间的部分T
。
$ faketime 2019-08-14 that-script your-file
14.08.2019
18.08.2019
20.08.2019
答案2
使用 GNU awk
,或mawk
:
$ cat file
30.07.2018
13.08.2019
14.08.2019
18.08.2019
20.08.2019
21.08.2019
23.08.2019
24.08.2019
25.08.2019
01.01.2020
$ awk -f script.awk file # running this on 2019-08-14
30.07.2018 expired 380 days ago
13.08.2019 expired 1 days ago
14.08.2019 expires in 0 days
18.08.2019 expires in 4 days
20.08.2019 expires in 6 days
21.08.2019 expires in 7 days
23.08.2019 expires in 9 days
24.08.2019 expires in 10 days
这将以与输入数据相同的顺序输出日期,每个日期都带有一个选项卡和一条短消息后缀。未来十一天或更长时间的日期将不会被输出。
剧本awk
:
BEGIN {
FS = "."
now = systime()/(24*60*60) - 1
}
{
datespec = sprintf("%s %s %s 00 00 00", $3, $2, $1)
timestamp = mktime(datespec)/(24*60*60)
diff = timestamp - now
if (diff < 0)
message = sprintf("expired %d days ago", 1 - diff)
else if (diff < 11)
message = sprintf("expires in %d days", diff)
else
next
printf("%s\t%s\n", $0, message)
}
mawk
GNUawk
已扩展了与日期/时间相关的函数,这里我们使用systime()
UNIX 时间戳来获取当前时间(自 1970 年 1 月 1 日 00:00 以来的秒数)。我们通过除以一天中的秒数将其四舍五入为一整天。
对于每个输入行,我们使用三个点分隔的数字 来mktime()
创建给定日期午夜(一天的开始)的 UNIX 时间戳,并将其四舍五入为完整天数,并将now
其称为timestamp
。
然后就是根据它们的不同之处进行比较now
并timestamp
找出要打印的内容。
请参阅 GNU 文档awk
或mawk
了解它们如何记录systime()
和mktime()
。
通过计算相应的 UNIX 时间戳对日期进行排序,以此为日期添加前缀,按数字排序,并丢弃现在使用的时间戳(使用mawk
或 GNU awk
):
$ awk -F . -v OFS="\t" '{ print mktime(sprintf("%d %d %d 00 00 00", $3, $2, $1)), $0 }' file | sort -n | cut -f 2
30.07.2018
13.08.2019
14.08.2019
18.08.2019
20.08.2019
21.08.2019
23.08.2019
24.08.2019
25.08.2019
01.01.2020
相同的事情,但更简单,并且也适用于 BSD awk
:
$ awk -F . -v OFS="\t" '{ print sprintf("%s-%s-%s", $3, $2, $1), $0 }' file | sort | cut -f 2
30.07.2018
13.08.2019
14.08.2019
18.08.2019
20.08.2019
21.08.2019
23.08.2019
24.08.2019
25.08.2019
01.01.2020
只需将日期转换为 YYYY-MM-DD (ISO 8601 日历日期) 格式并按字典顺序排序,而不是 UNIX 时间戳。
从一开始就使用 YYYY-MM-DD 日期格式会使排序变得更加简单,但我们仍然需要进行与awk
上面第一个脚本中相同的计算,以便能够(轻松地)说“这一天更不到 10 天的未来”。
答案3
如果我很好地理解你的话,我已经想到了这一点,并以@Kunasalanda 的答案为例:
这是使用 bash(或兼容的 shell)和 GNU date。它会在例如 macOS(非 GNU 日期)上失败。
today=$(date -d $(date +'%Y-%m-%d') +%s)
while read i; do
[[ -z "$i" ]] && continue
date_format=$(echo "$i" | awk -F'.' -vOFS='-' '{print $3,$2,$1}')
convert_date=$(date -d "$date_format" +%s)
if [[ "$convert_date" -ge "$today" ]]; then
expires=$(( ("$convert_date"- "$today")/86400 ))
[[ ! "$expires" -gt 10 ]] && echo $i expires in $expires days
fi
done < file
输出:
14.08.2019 expires in 0 days
18.08.2019 expires in 4 days
20.08.2019 expires in 6 days
忽略空行
[[ -z "$i" ]] && continue
格式化dd.mm.yy
为yyyy-mm-dd
能够执行操作
date_format=$(echo "$i" | awk -F'.' -vOFS='-' '{print $3,$2,$1}')
将日期转换为秒
convert_date=$(date -d "$date_format" +%s)
仅选择大于今天的日期
if [[ "$convert_date" -ge "$today" ]]; then
获取给定日期的到期天数
expires=$(( ("$convert_date"- "$today")/86400 ))
仅当到期时间不超过 10 天时输出
[[ ! "$expires" -gt 10 ]] && echo "$i" expires in "$expires" days