我正在尝试操作cal
命令,在一行中提供带有日期和星期几下方的输出,以便我可以在 excel 中将其用于脚本或 html。就像下面这样。
Wed Thu Fri Sat Sun Mon Tue Wed
1 2 3 4 5 6 7 8
答案1
使用bash
(或ksh93
) 和 GNU date
:
for (( i = 0; i < 8; ++i )); do
printf '%s\t' "$( date -d "now +$i days" +"%a" )"
done
echo
for (( i = 0; i < 8; ++i )); do
printf ' %d\t' "$( date -d "now +$i days" +"%e" )"
done
echo
该%a
格式将为您提供当前区域设置中星期几的缩写,同时%e
为您提供整数形式的月份中的某一天。
结果(制表符分隔):
Tue Wed Thu Fri Sat Sun Mon Tue
7 8 9 10 11 12 13 14
ksh93
评论后更新:(注意,这不起作用,因为 shell 似乎无法正确验证日期)
#!/bin/ksh93
yearmonth=$( date +"%Y%m" )
d=1
while printf '%(%a)T\t' "$( printf '%s%02d' "$yearmonth" "$d" )" 2>/dev/null
do
(( ++d ))
done
echo
days_this_month=$(( --d ))
while (( d > 0 )); do
printf ' %d\t' "$(( days_this_month - (--d) ))"
done
echo
yearmonth
首先在格式上设置为当前年份和月份YYYYMM
。然后我循环遍历这个月的所有工作日。循环设置wday
为缩写的工作日,当我尝试获取无效日期的工作日时,它将终止。
第二个循环只打印整数,与我们需要填写的月份一样多。
2017 年 2 月产出:
Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue
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
ksh93
使用Perl 和 Date::Calc 的解决方案:
#!/bin/ksh93
ym=( $(date +"%Y %m") )
days=$( perl -MDate::Calc -e 'print Date::Calc::Days_in_Month($ARGV[0],$ARGV[1])' -- "${ym[0]}" "${ym[1]}" )
for d in {1..$days}; do
printf '%(%a)T\t' "$( printf '%d-%d-%02d' "${ym[@]}" "$d" )"
done
echo
for d in {1..$days}; do
printf '%d\t' "$d"
done
echo
答案2
单独使用zsh
(仅内置):
#! /bin/zsh -
zmodload zsh/datetime
now=$EPOCHSECONDS
strftime -s year %Y $now
strftime -s month %m $now
strftime -rs s %Y,%m,%d,%H $year,$month,1,12
output=()
while
for field (a d m) strftime -s $field %-$field $s
((month == m))
do
output+=($a $((d)))
((s += 86400))
done
print -C $(($#output / 2)) $output
单独使用bash
(4.2 或更高版本)(仅内置),但假设工作日缩写为 3 个字符或更少,并且仅在您的语言环境中全部由单字节字符组成(因此在除英语之外的许多语言环境中无法正常工作) 。
#! /bin/bash -
printf -v now '%(%s)T' -1
printf -v d '%(%-d)T' "$now"
printf -v h '%(%-H)T' "$now"
printf -v month '%(%-m)T' "$now"
s=$((now +(12-h)*3600 - (d-1) * 86400))
l1= l2=
while
for field in a d m; do printf -v "$field" "%(%-$field)T" "$s"; done
((month == m))
do
printf -v l1 '%s%-3s ' "$l1" "$a"
printf -v l2 '%s%-3s ' "$l2" "$d"
((s += 86400))
done
printf '%s\n' "$l1" "$l2"
答案3
您也可以直接从卡尔输出,如下:
>cal|sed -n '2p;/_/p'
Su Mo Tu We Th Fr Sa
5 6 7 8 9 10 11
(但请注意,卡尔将使用两个字母的工作日缩写,至少在我的系统上)
答案4
$ cal | perl -0ne '
if(/(.*)(Su.*?)\n(\h*)( 1.*?)\s*$/s){
$s= length($3);
$b=$2 x 5;
$n= $4 =~ s/[^\d ]//gr;
print substr($b,$s,length($n)),"\n$n\n" }'
We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu
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
说明:cal的输出除以正则表达式(.*)(Su.*?)\n(\h*)( 1.*?)
Febr 2017 \nSu Mo Tu We Th Fr Sa \n 1 2 3 4 \n 5 6 7 8 9 10 11 ...
($1 )($2 ) ($3 )($4 ... )
$2
用于构建周栏 ($b = $2 x 5
)$4
\n
用于在删除并突出显示字符 ($n= $4 =~ s/[^\d ]//gr
)后构建日期列表- 的长度
$3
用于从周栏中删除最后一个月的天数 (substr($b,$s,length($n))
)