当两个命令各做一件你想做的事情但两者都不做时,你难道不喜欢这样吗?
这就是作用cal
。格式不错。但缺少周数:
$ cal
January 2012
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
这就是作用ncal
。奇怪的格式,但有周数:
$ ncal -w
January 2012
Su 1 8 15 22 29
Mo 2 9 16 23 30
Tu 3 10 17 24 31
We 4 11 18 25
Th 5 12 19 26
Fr 6 13 20 27
Sa 7 14 21 28
1 2 3 4 5
我想要的输出类型,实际上是cal
和之间的杂交ncal -w
:
$ cal --magik-calendar-week-option
January 2012
Su Mo Tu We Th Fr Sa
1 1 2 3 4 5 6 7
2 8 9 10 11 12 13 14
3 15 16 17 18 19 20 21
4 22 23 24 25 26 27 28
5 29 30 31
답변1
如果这些命令都不适合您的需要,您可以使用它gcal
来执行您想要的操作。
例子
$ gcal -K
April 2014
Su Mo Tu We Th Fr Sa CW
1 2 3 4 5 13
6 7 8 9 10 11 12 14
13 14 15 16 17 18 19 15
20 21 22 23 24 25 26 16
27 28 29 30 17
在右侧打印最后一列中的周数。
笔记: gcal
在大多数包管理器中都可用,例如brew install gcal
、apt install gcal
、dnf install gcal
等。
参考
답변2
这会突出显示今天的日期,并且可以通过$1
以下形式显示任何月份:YYYY-mm-dd
...默认为今天的日期
它被设置为显示 ISO 周数,第一个工作日是星期一。
#!/bin/bash
# Input reference date is expected in 'YYYY-mm-dd' format
#
today=($(date '+%Y %m %d')); Y=0; m=1; d=2 # establish today's date
[[ -z $1 ]] && ref=(${today[@]}) || ref=(${1//-/ }) # get input date
dNbA=$(date --date="$(date +%Y-%m-01)" +'%u') # day-number of 1st day of reference month
today[m]=$((10#${today[m]})); ref[m]=$((10#${ref[m]})) # remove leading zero (octal clash)
today[d]=$((10#${today[d]})); ref[d]=$((10#${ref[d]})) # remove leading zero (octal clash)
nxtm=$(( ref[m]==12 ?1 :ref[m]+1 )) # month-number of next month
nxtY=$(( ref[m]==12 ?ref[Y]+1:ref[Y] )) # year-number of next month
nxtA="$nxtY-$nxtm-1" # date of 1st day of next month
refZ=$(date --date "$(date +$nxtA) yesterday" +%Y-%m-%d) # date of last day of reference month
days=$(date --date="$refZ" '+%d') # days in reference month
h1="$(date --date="${ref[Y]}-${ref[m]}-${ref[d]}" '+%B %Y')" # header 1
h2="Mo Tu We Th Fr Sa Su" # header 2
printf " %$(((${#h2}-${#h1}-1)/2))s%s\n" " " "$h1"
printf " %s\n" "$h2"
# print week rows
printf "%2d " "$((10#$(date -d "$(date +${ref[Y]}-${ref[m]}-01)" +'%V')))" # week-number (of year) with suppressed leading 0
printf "%$(((dNbA-1)*3))s" # lead spaces (before start of month)
dNbW=$dNbA # day-number of week
dNbM=1 # day-number of month
while ((dNbM <= days)) ;do
if (( today[Y]==ref[Y] &&
today[m]==ref[m] &&
today[d]==dNbM )) ;then
printf "\x1b[7m%2d\x1b[0m " "$dNbM" # highlight today's date
else
printf "%2d " "$dNbM"
fi
((dNbM++))
if ((dNbW >=7)) ;then
cdate=$((10#$(date -d "$(date +${ref[Y]}-${ref[m]}-$dNbM)" +'%V'))) # remove leading zero (octal clash)
printf "\n%2d " "$cdate" # week-number of year
dNbW=0
fi
((dNbW++))
done
printf "%$(((8-dNbW)*3))s\n" # trailing spaces (after end of month)
这是本月的显示(20
突出显示)
January 2012
Mo Tu We Th Fr Sa Su
52 1
1 2 3 4 5 6 7 8
2 9 10 11 12 13 14 15
3 16 17 18 19 20 21 22
4 23 24 25 26 27 28 29
5 30 31
답변3
您可以使用nl
对行进行编号(这就是程序的目的:)。但是您需要从某个地方提取该月的第一周。它可以由它自己完成ncal
:
$ ncal -w 2 2012 | tail -1 | awk '{print $1}'
5
我们将其作为参数插入到 的nl
选项-v
(起始行号)中,并告诉它仅对带有数字或空格的行进行编号。
$ cal 2 2012 | nl -bp'^[0-9 ]\+$' -w2 -s' ' -v$(ncal -w 2 2012 | tail -1 | awk '{print $1}')
February 2012
Su Mo Tu We Th Fr Sa
5 1 2 3 4
6 5 6 7 8 9 10 11
7 12 13 14 15 16 17 18
8 19 20 21 22 23 24 25
9 26 27 28 29
但这一切都非常脆弱。无论如何,如果您不需要cal
更高级的选项,它就可以了。您可以将其放入文件中并替换"$@"
我放置的位置2 2012
。
编辑:但是这是错误的!我刚刚注意到一月份的第一周可能有数字 52 或 53!所以我们要么必须在一月份破例,要么只是提取全部来自 的周数ncal
并将其应用于 的输出cal
。
这是我最初想到的解决方案,但我认为(错误地)我会使用nl
.它使用paste
,并排合并文件。由于没有任何文件,我们必须使用 bashism <(...)
;这就是我试图避免的。
我们的第一个“文件”将是周数的列表,开头有两个空行:
$ printf ' \n \n' && printf '%2d \n' $(ncal -w 1 2011 | tail -1)
52
1
2
3
4
5
第二个,只是 的输出cal
。全部一起作为参数paste
:
$ paste -d' ' <(printf ' \n \n' && printf '%2d \n' $(ncal -w 1 2011 | tail -1)) <(cal 1 2011)
January 2011
Su Mo Tu We Th Fr Sa
52 1
1 2 3 4 5 6 7 8
2 9 10 11 12 13 14 15
3 16 17 18 19 20 21 22
4 23 24 25 26 27 28 29
5 30 31
比另一个更混乱和不兼容。恩...
답변4
使用 Perl 的一种方法(我的命令输出语言cal
是西班牙语,但我希望结果不会与英语不同):
$ cal | perl -pe 'if ( m/\A\s*\d/ ) { s/\A/++$i . qq[ ] x 2/e } else { s/\A/qq[ ] x 3/e }'
输出:
enero de 2012
lu ma mi ju vi sá do
1 1
2 2 3 4 5 6 7 8
3 9 10 11 12 13 14 15
4 16 17 18 19 20 21 22
5 23 24 25 26 27 28 29
6 30 31
解释:
-pe # For every input line from previous pipe, execute next
# instructions and print to output.
if ( m/\A\s*\d/ ) # If line begins with a digit omitting spaces...
s/\A/++$i . qq[ ] x 2/e # Insert at the beginning of the line a counter plus two spaces.
else # else...
s/\A/qq[ ] x 3/e # Insert three spaces at the beginning of the line.