![使用 bash 中的 cal 函数挑选“第一个”日期](https://linux22.com/image/143270/%E4%BD%BF%E7%94%A8%20bash%20%E4%B8%AD%E7%9A%84%20cal%20%E5%87%BD%E6%95%B0%E6%8C%91%E9%80%89%E2%80%9C%E7%AC%AC%E4%B8%80%E4%B8%AA%E2%80%9D%E6%97%A5%E6%9C%9F.png)
我试图从cal
函数和管道awk
命令中挑选出第一个星期一、第二个星期二、第二个星期六等。这个月我可以获得第一个星期二正确使用日历下面的命令:
December 2018
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
>cal | awk 'NF == 7 && NR > 2 {print $3; exit}'
>4
但这并不总是有效,请参阅下面 2016 年 3 月的测试:
March 2016
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
>cal 3 2016 | awk 'NF == 7 && NR > 2 {print $3; exit}'
>8
为什么它适用于顶部示例而不适用于底部示例?我认为底部的示例应该查看第三行并找到 的正确结果1
。有没有一种万无一失的方法可以使用awk
- 也许检查该列是否为空并移动到下一行来获取这些日期?
答案1
这是为您提供的另一个解决方案
cal | awk 'NR >= 3 { tu = substr($0,7,2) +0 } tu { print tu; exit }'
4
cal 3 2016 | awk 'NR >= 3 { tu = substr($0,7,2) +0 } tu { print tu; exit }'
1
它挑选出星期二列(字符 7 和 8),并提供第一个非零值。该方法可以安全地推断到一周中的任何一天。
答案2
使用 GNU 日期:
对于当月的第一个星期二:
for day in 0{1..7}; do [[ "$(date -d $(date +%Y%m${day}) +%a)" = "Tue" ]] && echo "$day";done
对于给定年份和月份的第一个星期二:
year=2016
month=03
for day in 0{1..7}; do [[ "$(date -d ${year}${month}${day} +%a)" = "Tue" ]] && echo "$day";done
awk 中的“星期二”变体:
cal | awk -F "" '!/[[:alpha:]]/ && $7$8 ~ /[0-9]/ { print $7$8;exit }'
这将检查输出中第 7 列和第 8 列(星期二)的硬编码位置(请注意,字段分隔符为空,将输入拆分为每个字符)——在跳过任何包含字母的行(标题行)之后。调整 7 和 8 以获得其他日期。
为了更清楚地显示上一个命令正在执行的操作,awk 命令的字段按列编号:
123456789 <--- awk fields $1, $2, $3, ... $9
December 2018
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
答案3
gcal
(GNU) 和(BSD) 系列都ncal
支持转置行与列的选项:
$ ncal
March 2024
Su 3 10 17 24 31
Mo 4 11 18 25
Tu 5 12 19 26
We 6 13 20 27
Th 7 14 21 28
Fr 1 8 15 22 29
Sa 2 9 16 23 30
$ gcal -i
March 2024
Sunday 3 10 17 24 31
Monday 4 11 18 25
Tuesday 5 12 19 26
Wednesday 6 13 20 27
Thursday 7 14 21 28
Friday 1 8 15 22 29
Saturday 2 9 16 23 30
当以这种方式调用时,可以更轻松地按星期几选择顺序位置。首先使用awk
模式匹配所需的一周中的某一天,然后打印 N-1 列以获取一周中该天的第 N 个实例。
例如,特定月份和年份的第一个星期二:
$ ncal 12 2018 | awk '/^Tu/ { print $2; }'
4
$ ncal 3 2016 | awk '/^Tu/ { print $2; }'
1
要获取当月的第 5 个星期五(恰好有一个):
$ ncal | awk '/^Fr/ { print $6; }’
29
答案4
在 ksh93 中:
$ printf '%(%F)T\n' 'first monday this month'
2024-03-04
$ printf '%(%F)T\n' 'second tuesday this month'
2024-03-12
$ printf '%(%F)T\n' '2nd tuesday in 2016-03'
2016-03-08
(注意第 4、5 个在当前版本的 ksh93u+m 中不起作用; fourth
,fifth
尽管如此)。