3 ms·
> Heres a solution that uses only sh and portable sed. No awk. No wc. No, it isn't! :) The challenge was specifically about joining the months of `cal -y` int
by jolmg 5y ago
> Heres a solution that uses only sh and portable sed. No awk. No wc.
No, it isn't! :)
The challenge was specifically about joining the months of `cal -y` into a single column with sed. It's about the challenge of working with a grid of grids, with the restrictive nature of sed, having only one hold-space to hold 2 months separately. You totally missed doing that with your solution. Of course, it's loads easier to just skip the challenge altogether!
Maybe the point of the sed challenge wasn't clear. It's about stretching the abilities of sed to its limits. Of being able to use all its features to its fullest. I think this is the first time that I had a real use for m~n, and I still haven't found a good use for `D` or `P`.
EDIT: You're using `cal -y` now, but you've still gone outside the challenge space:
> what kind of sed script I’d need in the middle of a `cal -y | ... | wc -l` pipeline to get the same answer
Meaning the working space is just substituting the ellipses for `sed` commands. It's a single `cal -y` call, a single `wc -l` call, and no other shell code except pipes.
I did an awk command in the last bit, but here is the sed equivalent:
sed -E '
/[a-z]$/{h;s/.* //;x}
/[a-z]$/!G
/\b7\b.*July/,/20.*August/!d
s/\n.*//
'
Ideally, it was supposed to be just a single sed command, but I wanted to try out the org-mode blocks for showing the process in multiple stages and also use the m~n addresses, which it seemed like I wouldn't be able to if I did the single call.
- 1vuio0pswjnm7 5y agoThis solution uses temp files: 111, and 111-a through 111-l. 111 is the full calendar, the others are individual months. No dependence on any GNU sed features. Will work with GNU sed, BSD sed and Plan9 sed. Uses only sed commands and pipes, single cal -y, sed instead of wc. test $# -eq 4||exec echo usage: $0 7 jul 20 aug; x=$(echo $2 $4|sed -n '/[A-Z]/p'); if test "$x";then echo use lowercase;exit;fi cal -y \ |sed -n -e "w 111" \ -e "3,10{s/\(.\{23\}\)\(.*\)/\1/w 111-a }" -e "r 111"|sed -n \ -e "3,10{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-b }" -e "3,10r 111"|sed -n \ -e "3,10{s/.\{46\}//w 111-c }" -e "3,10r 111"|sed -n \ -e "11,18{s/\(.\{23\}\)\(.*\)/\1/w 111-d }" -e "11,18r 111"|sed -n \ -e "11,18{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-e }" -e "11,18r 111"|sed -n \ -e "11,18{s/.\{46\}//w 111-f }" -e "11,18r 111"|sed -n \ -e "19,26{s/\(.\{23\}\)\(.*\)/\1/w 111-g }" -e "19,26r 111"|sed -n \ -e "19,26{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-h }" -e "19,26r 111"|sed -n \ -e "19,26{s/.\{46\}//w 111-i }" -e "19,26r 111"|sed -n \ -e "27,34{s/\(.\{23\}\)\(.*\)/\1/w 111-j }" -e "27,34r 111"|sed -n \ -e "27,34{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-k }" -e "27,34r 111"|sed -n \ -e "27,34{s/.\{46\}//w 111-l }" -e "27,34r 111"|sed '2,$d' \ |sed -e "r 111-a" -e "r 111-b" -e "r 111-c" \ -e "r 111-d" -e "r 111-e" -e "r 111-f" \ -e "r 111-g" -e "r 111-h" -e "r 111-i" \ -e "r 111-j" -e "r 111-k" -e "r 111-l" \ |sed '/^Su/d;/^ *$/d;/^ *[A-S]/s/^/@/ /Jan/,/Feb/s/$/ jan /; /Feb/,/Mar/s/$/ feb /; /Mar/,/Apr/s/$/ mar /; /Apr/,/May/s/$/ apr /; /May/,/Jun/s/$/ may /; /Jun/,/Jul/s/$/ jun /; /Jul/,/Aug/s/$/ jul /; /Aug/,/Sep/s/$/ aug /; /Sep/,/Oct/s/$/ sep /; /Oct/,/Nov/s/$/ oct /; /Nov/,/Dec/s/$/ nov /; /Dec/,$s/$/ dec /;/@/d' \ |sed -n "/ $1 .*$2/,/ $3 .*$4/{ / 1 /d;p;}"|sed -n '$='; rm 111 111-[a-l]
- jolmg 5y agoThat's good! I didn't think to use the `r` and `w` commands. There's only the problem that because of `-n`, it doesn't output anything.
- 1vuio0pswjnm7 5y agoThis outputs the calendar dates to standard error. test $# -eq 4||exec echo usage: $0 7 jul 20 aug; x=$(echo $2 $4|sed -n '/[A-Z]/p'); if test "$x";then echo use lowercase;exit;fi cal -y \ |sed -n -e "w 111" \ -e "3,10{s/\(.\{23\}\)\(.*\)/\1/w 111-a }" -e "r 111"|sed -n \ -e "3,10{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-b }" -e "3,10r 111"|sed -n \ -e "3,10{s/.\{46\}//w 111-c }" -e "3,10r 111"|sed -n \ -e "11,18{s/\(.\{23\}\)\(.*\)/\1/w 111-d }" -e "11,18r 111"|sed -n \ -e "11,18{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-e }" -e "11,18r 111"|sed -n \ -e "11,18{s/.\{46\}//w 111-f }" -e "11,18r 111"|sed -n \ -e "19,26{s/\(.\{23\}\)\(.*\)/\1/w 111-g }" -e "19,26r 111"|sed -n \ -e "19,26{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-h }" -e "19,26r 111"|sed -n \ -e "19,26{s/.\{46\}//w 111-i }" -e "19,26r 111"|sed -n \ -e "27,34{s/\(.\{23\}\)\(.*\)/\1/w 111-j }" -e "27,34r 111"|sed -n \ -e "27,34{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-k }" -e "27,34r 111"|sed -n \ -e "27,34{s/.\{46\}//w 111-l }" -e "27,34r 111"|sed '2,$d' \ |sed -e "r 111-a" -e "r 111-b" -e "r 111-c" \ -e "r 111-d" -e "r 111-e" -e "r 111-f" \ -e "r 111-g" -e "r 111-h" -e "r 111-i" \ -e "r 111-j" -e "r 111-k" -e "r 111-l" \ |sed '/^Su/d;/^ *$/d;/^ *[A-S]/s/^/@/ /Jan/,/Feb/s/$/ jan /; /Feb/,/Mar/s/$/ feb /; /Mar/,/Apr/s/$/ mar /; /Apr/,/May/s/$/ apr /; /May/,/Jun/s/$/ may /; /Jun/,/Jul/s/$/ jun /; /Jul/,/Aug/s/$/ jul /; /Aug/,/Sep/s/$/ aug /; /Sep/,/Oct/s/$/ sep /; /Oct/,/Nov/s/$/ oct /; /Nov/,/Dec/s/$/ nov /; /Dec/,$s/$/ dec /;/@/d' \ |sed -n -e "/ $1 .*$2/,/ $3 .*$4/{ w /dev/stderr / 1 /d;p;}"|sed -n '$=' or to output the calendar dates to standard out, add another temp file, 111-z test $# -eq 4||exec echo usage: $0 7 jul 20 aug; x=$(echo $2 $4|sed -n '/[A-Z]/p'); if test "$x";then echo use lowercase;exit;fi cal -y \ |sed -n -e "w 111" \ -e "3,10{s/\(.\{23\}\)\(.*\)/\1/w 111-a }" -e "r 111"|sed -n \ -e "3,10{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-b }" -e "3,10r 111"|sed -n \ -e "3,10{s/.\{46\}//w 111-c }" -e "3,10r 111"|sed -n \ -e "11,18{s/\(.\{23\}\)\(.*\)/\1/w 111-d }" -e "11,18r 111"|sed -n \ -e "11,18{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-e }" -e "11,18r 111"|sed -n \ -e "11,18{s/.\{46\}//w 111-f }" -e "11,18r 111"|sed -n \ -e "19,26{s/\(.\{23\}\)\(.*\)/\1/w 111-g }" -e "19,26r 111"|sed -n \ -e "19,26{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-h }" -e "19,26r 111"|sed -n \ -e "19,26{s/.\{46\}//w 111-i }" -e "19,26r 111"|sed -n \ -e "27,34{s/\(.\{23\}\)\(.*\)/\1/w 111-j }" -e "27,34r 111"|sed -n \ -e "27,34{s/\(.\{23\}\)\(.\{20\}\)\(.*\)/\2/w 111-k }" -e "27,34r 111"|sed -n \ -e "27,34{s/.\{46\}//w 111-l }" -e "27,34r 111"|sed '2,$d' \ |sed -e "r 111-a" -e "r 111-b" -e "r 111-c" \ -e "r 111-d" -e "r 111-e" -e "r 111-f" \ -e "r 111-g" -e "r 111-h" -e "r 111-i" \ -e "r 111-j" -e "r 111-k" -e "r 111-l" \ |sed '/^Su/d;/^ *$/d;/^ *[A-S]/s/^/@/ /Jan/,/Feb/s/$/ jan /; /Feb/,/Mar/s/$/ feb /; /Mar/,/Apr/s/$/ mar /; /Apr/,/May/s/$/ apr /; /May/,/Jun/s/$/ may /; /Jun/,/Jul/s/$/ jun /; /Jul/,/Aug/s/$/ jul /; /Aug/,/Sep/s/$/ aug /; /Sep/,/Oct/s/$/ sep /; /Oct/,/Nov/s/$/ oct /; /Nov/,/Dec/s/$/ nov /; /Dec/,$s/$/ dec /;/@/d' \ |sed -n -e "/ $1 .*$2/,/ $3 .*$4/{ w 111-z / 1 /d;p;}"|sed -n -e '$=' -e "1r 111-z"
- heresie-dabord 5y agoUnder the heavily populated category of Solutions That Aren't, here's my approach. ^_^ Use ncal because it provides the week numbers and can start weeks on Monday (personal preference). Pipe to sed, fold, and then to Perl. (Perl is awesome.) ncal -w -3 -y -b -h -M | sed 's/ /*/g' | fold -w 27 | tail -n 99 | perl -w -e 'use strict; my (@g1,@g2,@g3,@aAccum)=((),(),(),()); my $tog=1; sub clearQ{ (@g1,@g2,@g3)=((),(),());} sub doAccum{ @aAccum=(@g1,@g2,@g3); clearQ(); print @aAccum; @aAccum=(); } for my $wk(<>){ my $LN=$wk; chomp($LN); if( length($LN)==0 ){ doAccum(); next;} if($tog==1){push @g1,$wk;} elsif($tog==2){push @g2,$wk;} elsif($tog==3){push @g3,$wk;} $tog++; if($tog>3){ $tog=1;} } doAccum();'
- 1vuio0pswjnm7 5y ago"Use ncal because it provides week numbers and can start weeks on Monday (personal preference)." Use the cal that is in util-linux: https://www.kernel.org/pub/linux/utils/util-linux/ https://www.kernel.org/pub/linux/utils/util-linux/ cal -m starts weeks on Monday. cal -w displays week numbers. Personal preference is not to install Perl unless needed, e.g., for compiling OpenSSL. Takes up precious space that can be used for other things.
- heresie-dabord 5y agoIn *buntu 20.04, I have cal and ncal. But yes, any common cal utility that generates week numbers is a better solution than cal -y | ... | wc -l. I understand your preference for a lean file system. In this challenge, I needed more than awk (because of arrays) and wanted an explicit solution that works regardless of calendar language.