シェル芸160本ノック解答例 その7

技術評論社から出版された『1日1問、半年以内に習得 シェル・ワンライナー160本ノック』の解答例です。


問題61

# 現在の日付、時刻、曜日を確認
$ date
2022年 10月 27日 木曜日 22:10:07 JST
$ cal
      10月 2022
日 月 火 水 木 金 土
                   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

# 解答用のダミーファイルを生成
$ seq -f "$(date +%F) %g hour" 0 -1 -400 | date -f - '+touch -t %Y%m%d%H%M %F_%T' | sh

# 解答例のワンライナーを実行
$ LANG=C ls -l | grep -f <(dateutils.dadd today -7d | pee 'dateutils.dround -- -Sun' 'dateutils.dround +Sat' | xargs dateutils.dseq -f '%b %d') | sed 's/.* //'
2022-10-16_00:00:00
2022-10-16_01:00:00
2022-10-16_02:00:00
(...略...)
2022-10-22_21:00:00
2022-10-22_22:00:00
2022-10-22_23:00:00

問題62

$ join -a1 -t, <(dateutils.dseq 2019-01-01 2021-12-31) <(nkf -wxLu syukujitsu.csv | awk -F '[/,]' '{printf "%d-%02d-%02d,%s\n",$1,$2,$3,$4}') | sed '/,/!s/$/,@/'
2019-01-01,元日
2019-01-02,@
2019-01-03,@
(...略...)
2021-11-22,@
2021-11-23,勤労感謝の日
2021-11-24,@
(...略...)
2021-12-29,@
2021-12-30,@
2021-12-31,@

問題63

$ for m in {01..12}; do ncal -d 2021-$m | awk 'NR<2{m=$1}/^日/&&NF==6{print m}'; done
1月
5月
8月
10月

問題64

$ for m in {01..12}; do ncal -d 2021-$m | awk 'NR<2{Y=$2 "年";m=$1}/^火/{print Y m $4 "日"}'; done
2021年1月19日
2021年2月16日
2021年3月16日
2021年4月20日
2021年5月18日
2021年6月15日
2021年7月20日
2021年8月17日
2021年9月21日
2021年10月19日
2021年11月16日
2021年12月21日

問題65

$ cat <(dateutils.dseq -s Mon-Fri 2019-01-01 2019-12-31) <(nkf -wxLu syukujitsu.csv | awk -F/ '/2019/{printf "%d-%02d-%02d\n",$1,$2,$3}') | sort -u | awk -F- '{h[$1"-"$2]+=1}END{for(Ym in h)print Ym": "h[Ym]}' | sort
2019-01: 10
2019-02: 9
2019-03: 11
2019-04: 10
2019-05: 12
2019-06: 10
2019-07: 9
2019-08: 10
2019-09: 11
2019-10: 10
2019-11: 10
2019-12: 9

問題66

# `2017-09-18`の翌週の火曜
$ dateutils.dadd 2017-09-18 1w | dateutils.dround Tue
2017-09-26

# `2017-09-18`の翌々週の金曜
$ dateutils.dadd 2017-09-18 1w | dateutils.dround Tue | dateutils.dadd 1w | dateutils.dround Fri
2017-10-06

# 解答例となる最終的なワンライナー:
# `2017-09-18`の翌々週の金曜の前日(打ち合わせの日)
$ dateutils.dadd 2017-09-18 1w | dateutils.dround Tue | dateutils.dadd 1w | dateutils.dround Fri | dateutils.dadd -1d
2017-10-05

# おまけのワンライナー:
# `2017-09-18`の翌週の火曜、翌々週の金曜、翌々週の金曜の前日、これら3つを一気に出力
$ dateutils.dadd 2017-09-18 1w | dateutils.dround Tue | pee cat 'dateutils.dadd 1w | dateutils.dround Fri | pee cat "dateutils.dadd -1d"'
2017-09-26
2017-10-06
2017-10-05

問題67

$ paste <(date +%a -f <(sed 's/ .*//' dinner)) dinner | awk '{print $2,$3 > $1}'

このワンライナーを実行してdinnerから生成された曜日別のファイルを確認します。

$ head 月 火 水 木 金 土 日
==> 月 <==
20190107 焼肉
20190114 焼肉

==> 火 <==
20190101 たまごかけごはん
20190108 たまごかけごはん

==> 水 <==
20190102 納豆ごはん

==> 木 <==
20190110 ミートボールスパ

==> 金 <==
20190111 ニシンのパイ

==> 土 <==
20190105 焼肉

==> 日 <==
20190106 断食
20190113 断食

問題68

次の2つの例のように、OSの環境などにより利用できるUnix時刻の最大値はそれぞれ異なっています。

  • 32ビット環境で解答例のワンライナーを実行した場合:

      $ ((b=(1<<63)-1)); t=0; m=0; while (((t>b?t-b:b-t)>1)); do ((m=(t-b)/2+b)); date -d@$m 2>/dev/null && { t=$m; echo $t; } || b=$m; done | tail -n2
      2038年  1月 19日 火曜日 12:14:07 JST
      2147483647
    
  • 64ビット環境で解答例のワンライナーを実行した場合:

      $ ((b=(1<<63)-1)); t=0; m=0; while (((t>b?t-b:b-t)>1)); do ((m=(t-b)/2+b)); date -d@$m 2>/dev/null && { t=$m; echo $t; } || b=$m; done | tail -n2
      2147485547年 12月 31日 水曜日 23:59:59 JST
      67768036191644399
    

問題69

$ seq 1972 $(date +%Y) | while read Y; do (TZ=right/Asia/Tokyo; T=08:59:60; TZ=$TZ date -d "$Y-01-01 $T"; TZ=$TZ date -d "$Y-07-01 $T") 2>/dev/null; done
1972年  7月  1日 土曜日 08:59:60 JST
1973年  1月  1日 月曜日 08:59:60 JST
1974年  1月  1日 火曜日 08:59:60 JST
1975年  1月  1日 水曜日 08:59:60 JST
1976年  1月  1日 木曜日 08:59:60 JST
1977年  1月  1日 土曜日 08:59:60 JST
1978年  1月  1日 日曜日 08:59:60 JST
1979年  1月  1日 月曜日 08:59:60 JST
1980年  1月  1日 火曜日 08:59:60 JST
1981年  7月  1日 水曜日 08:59:60 JST
1982年  7月  1日 木曜日 08:59:60 JST
1983年  7月  1日 金曜日 08:59:60 JST
1985年  7月  1日 月曜日 08:59:60 JST
1988年  1月  1日 金曜日 08:59:60 JST
1990年  1月  1日 月曜日 08:59:60 JST
1991年  1月  1日 火曜日 08:59:60 JST
1992年  7月  1日 水曜日 08:59:60 JST
1993年  7月  1日 木曜日 08:59:60 JST
1994年  7月  1日 金曜日 08:59:60 JST
1996年  1月  1日 月曜日 08:59:60 JST
1997年  7月  1日 火曜日 08:59:60 JST
1999年  1月  1日 金曜日 08:59:60 JST
2006年  1月  1日 日曜日 08:59:60 JST
2009年  1月  1日 木曜日 08:59:60 JST
2012年  7月  1日 日曜日 08:59:60 JST
2015年  7月  1日 水曜日 08:59:60 JST
2017年  1月  1日 日曜日 08:59:60 JST

問題70

# 1文字ずつをカンマで区切ったCSVファイルを生成する解答例のワンライナー
$ sed 's/./&\t/g;s/\t$//;s/"/"&&"/g;s/,/"&"/g;s/\t/,/g' excel_hogan.txt | nkf -sxLw > excel_hogan_sjis.csv

# 生成したCSVファイルの文字コードと改行コードを確認
$ nkf -g excel_hogan_sjis.csv
Shift_JIS
$ file excel_hogan_sjis.csv
excel_hogan_sjis.csv: Non-ISO extended-ASCII text, with CRLF line terminators

# 生成したCSVファイルの内容を確認
$ nkf -wxLu excel_hogan_sjis.csv
エ,ク,セ,ル,方,眼,紙,と,い,う,ど,う,し,よ,う,も,無,い
風,習,が,あ,り,ま,す,が,、,我,々,は,文,句,を,言,い,つ
つ,も,、,従,わ,ざ,る,を,得,な,い,状,況,に,し,ば,し,ば
立,た,さ,れ,ま,す,。,最,後,に,一,言,。
"""",N,o, ,h,o,g,a,n,",", ,n,o, ,l,i,f,e,.,""""
Written on November 2, 2022