使用ncal或cal以某种格式显示星期数


16

当两个命令各自执行您想要的一件事而两个都不都想要时,您是否就喜欢它?

这是做什么的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

Answers:


13

如果这些命令都不满足您的需求,则可以使用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 --starting-day=Monday --with-week-number更符合我的需求,但是这个工具很棒。
k0pernikus

9

这突出显示了今天的日期,并且可以通过$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                

我什至没有注意到同种异物。那会做的:)
k0pernikus 2012年

1
@ k0pernikus:我刚刚修改了剧本。(您发布的评论上方约35分钟后)..天色渐上赶上0809被解释为八进制,而不是小数。它应该是罚款,现在...
Peter.O 2012年

7

您可以使用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

比另一个更混乱和不兼容。恩...


不太好 :-/。看到我的编辑。
安格斯

7

生成周序列,ncalpaste用于将两个输出并排使用。

$ paste <(echo; echo; ncal -w | tail -1 | xargs -n1 printf '%2d\n') <(cal)

如果您不喜欢使用制表符作为分隔符,只需添加类似 sed 's/\t/ /'


编辑:方式更简单,无需关心选项卡:

$ paste -d' ' <((echo -n '   '; ncal -w | tail -1 )| fold -w 3) <(cal)

优雅,体现了ESR的17个Unix规则中的许多规则。应该被接受,因为它确实结合了cal和的输出ncal(其他方法复制了cal或的行为ncal)。
主教

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.

在接下来的几个月中将如何工作。2月的周不再从1开始,它们从5/6开始,同样,3月将从9/10开始。
Nikhil Mulley

cal 02 2012,会失败吗?
Nikhil Mulley

@Nikhil:我不明白你的意思。您可以尝试更深入地解释它吗?脚本是否会失败cal 02 2012?它在我的测试中似乎有效。
Birei 2012年

@Nikhil:好的。我误解了这个问题。它表示绝对周数,而不是相对于每月。我会在一段时间内删除我的错误答案。
Birei 2012年

1
酷..不要删除答案,请保留以供参考。
Nikhil Mulley

1

没有足够的代表评论slm 的答案,可以使用在Mac OS上安装gcalbrew install gcal

(我首先在这里找到了答案,然后在询问时得到了不同的答案,但是Unix答案缺少我需要在Mac上安装的所有信息。)


0

这是我的解决方案,它的代码较短,并且在其他日期比当前月份更好。抱歉,美国人使用ISO格式,即一周的第一天是星期一。使用cal的-m选项和date的%V选项来完成此操作

#!/bin/bash
if [ "$1" = "" ]
then
  when="now"
else
  when="$1"
fi
y=$(date --date "$when" +%Y )
if [ $? -ne 0 ]
then
  exit
fi
m=$(date --date "$when" +%m )
w=$(date --date $(printf %4d%02d01 $y $m) +%V)
cal -m $m $y |
  awk -v w=$w '
    NR>2{ww=w++}
    $0!=""{printf "%2s %s\n", ww , $0}
  '

0

我执行了此脚本以生成团队的值班日历。它会生成带有星期编号的日历,并为它们分配名称(简称循环)。输出输出后,您只需要将其复制到excel并按“从文本到列”即可;然后使用“固定”选项在第一列上再次执行“文本到列”。该日历的优点(与水平方向相比)是您可以使用自动过滤器(Alt + dff)并仅查找星期。

#!/ usr / bin / ksh
y = 2017
集-A team1佩塔尔斯·贾斯塔斯·理查德·尤卡·杰斯珀
集-A team2莫德斯塔斯·蒂莫·马特斯·安德里亚斯

i1 = 0
i2 = 0
wn = 1
拥有= 1

echo“ WN月Mo Tu We Th Fr Sa Su; Team1; Team2”
ycal =`for m in 1 2 3 4 5 6 7 8 9 10 11 12
做
IFS =
        cal -m $ m $ y | egrep -v“ Mo | ^ $” |同时读取行
        做
                echo $ line | grep -q $ y && mname = $ line || 打印$ mname $ line | sed's /'$ y'//'
        做完了
完成`
IFS =
在读取第2行时回显“ $ ycal” |
做
IFS =
        echo“ $ line2” | grep -v“ 1 2 3 4 5 6 7” | egrep -q“ * 1 | * 1 $” || 让wn ++
        [$ own -ne $ wn] && {
                [$ i1 -eq $ {#team1 [@]}-1] && i1 = 0 || 让i1 ++; \
                [$ i2 -eq $ {#team2 [@]}-1] && i2 = 0 || 让i2 ++; }
        printf'%2s%s;%s;%s \ n'$ wn $ line2 $ {team1 [$ i1]} $ {team2 [$ i2]}
        自己= $ wn
做完了

抱歉,代码有点令人讨厌...并且没有评论...但是效果很好;)


0

我不是真的想要安装gcal,也无法在系统上正常运行。因此,如果没有gcal,funollet的答案确实是最好的解决方案。我只是对其进行了少许更改,以便它还可以使用命令保留诸如日光 突出显示颜色等格式script。我还删除了多余的字符,使其适合用作别名,例如:

alias today="paste -d' ' <((echo ' '{,};ncal -w|tail -1)|fold -w3) <(script /dev/null -qc cal)"

或替换cal为新功能。但是,使用此功能无法执行cal -3。您得到了正确的星期,但它们的排列不正确。一个简单但不完整的解决方案是检查是否cal在不带参数的情况下进行调用,如下所示:

function cal {
    if [[ $# -eq 0 ]]; then
        paste -d' ' <((echo ' '{,};ncal -w $@|tail -1)|fold -w3) <(script /dev/null -qc "cal $@")
    else
        /usr/bin/cal "$@"
    fi
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.