hero_picture
Cover Image for 【linux shell】土日祝の休日一覧を自動でcsvにまとめて別のスクリプトで活用する方法

【linux shell】土日祝の休日一覧を自動でcsvにまとめて別のスクリプトで活用する方法

2023/01/17

クラウドソリューション事業部の倉岡です。前回、「【自動化】zabbixの障害一覧をbacklog課題にスクリプトで投稿する方法」で毎日の手作業から解放されたわけですが、1つ問題点が浮上しました。

土日は動かないようにクーロンで設定しているのですが月から金は基本的に動作するので、祝日や夏季休暇、年末・年始 休暇にも動作してしまう問題点があります。

さらに全く別の問題で、当月の下旬あたりにサーバー待機という翌月の土日祝にサーバー障害対応スタッフの人員を決めるものがあるのですが、一回一回月末に翌月の土日祝をカレンダーと睨めっこしながら手動でslackに書き込んでいくのが面倒です。

ということで今回は、両者の問題を解決すべく、土日祝、会社規定の休みを取得するスクリプトを作成しました。

目次1.準備する環境2.まずは土日祝日の取得スクリプト3.後は月から金に動作してるスクリプトに追加4.slackに翌月の祝日一覧を載せる

1.準備する環境

・linuxサーバー (土日祝の取得だけならこれだけ)

・slack api

2.まずは土日祝日の取得スクリプト

下準備として会社規定で決まっている夏季休暇、年末・年始 休暇の日付を書いたcsvファイル(seeds_holiday.csv)を作成します。

18/13
28/14
38/15
48/16
512/29
612/30
712/31
81/1
91/2
101/3

続いて本体となる「休みの日の一覧取得、csvに書き込みする」スクリプトの作成です。以下がスクリプトです。

以下のスクリプトを参考にして作成しました。

参考:Qiita | 日本の祝日を判定するBashスクリプトを書いた件

1#!/bin/bash
2LANG="ja_JP.UTF-8"
3#内閣府HPにて祝日一覧csv取得
4wget -P /home/hoge/server-taiki https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv
5PUBLIC_HOLIDAY_LIST=/home/hoge/server-taiki/syukujitsu.csv
6#シーズの会社規定の夏季休暇、年末・年始 休暇の取得
7SEEDS_HOLIDAY=/home/hoge/server-taiki/seeds_holiday.csv
8#閏年か確認
9if [[ $(($(date +'%Y') % 400 )) -eq 0 ]] ; then
10 DAYS=366
11elif [[ $(($(date +'%Y') % 100 )) -eq 0 ]] ; then
12 DAYS=365
13elif [[ $(($(date +'%Y') % 4 )) -eq 0 ]] ; then
14 DAYS=366
15else
16 DAYS=365
17fi
18
19echo -n > /home/hoge/server-taiki/holiday.csv
20
21for ((i=1 ; i<=${DAYS} ; i++))do
22#1年間分回して確認する
23target_date=$(date +"%Y/%-m/%-d" --date "${i} day")#夏季年始休暇の場合
24if [ -n "$(grep -x $(date +"%-m/%-d" --date "${i} day")  $SEEDS_HOLIDAY)" ] ; then
25    #会社規定の休みを取得
26    echo "${target_date}" >> /home/hoge/server-taiki/holiday.csv
27elif [ -n "$(grep $target_date"," $PUBLIC_HOLIDAY_LIST)" ] ; then
28    #祝日を取得
29    echo "${target_date}" >> /home/hoge/server-taiki/holiday.csv
30elif [ -n "$(date -d $target_date | grep -E "[土日]曜日")" ] ; then
31    #土日を取得
32    echo "${target_date}" >> /home/hoge/server-taiki/holiday.csv
33fi
34done
35#内閣府HPのcsvを削除
36rm -f /home/hoge/server-taiki/syukujitsu.csv

解説

dateコマンドを入力時、漢字の曜日が出力されるように日本語を選択します。

1LANG="ja_JP.UTF-8"

ここで内閣府HPから祝日一覧のcsvとシーズの規定休日の日付を取得して、各変数にcsvファイルを代入します。

1#内閣府HPにて祝日一覧csv取得
2wget -P /home/hoge/server-taiki https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv
3PUBLIC_HOLIDAY_LIST=/home/hoge/server-taiki/syukujitsu.csv
4#シーズの会社規定の夏季休暇、年末・年始 休暇の取得
5SEEDS_HOLIDAY=/home/hoge/server-taiki/seeds_holiday.csv

続いて閏年か確認しています。閏年の判定は、結構細かいです。その点を考慮した結果このようになりました。

💡
閏年の条件
  • 条件 1. 西暦年が400の倍数である場合、閏年
  • 条件 1. を満たさず(西暦年が400の倍数ではなく)、かつ西暦年が100の倍数である場合、平年
  • 条件 1. と 2. を両方とも満たさず(西暦年が100の倍数ではなく)、かつ西暦年が4の倍数である場合、閏年
  • 条件 1. 〜 3. を全て満たさない場合、平年

参考:https://www.weblio.jp/content/%E9%80%90%E6%AC%A1%E7%9A%84%E3%81%AA4%E6%9D%A1%E4%BB%B6

1#閏年か確認
2if [[ $(($(date +'%Y') % 400 )) -eq 0 ]] ; then
3 DAYS=366
4elif [[ $(($(date +'%Y') % 100 )) -eq 0 ]] ; then
5 DAYS=365
6elif [[ $(($(date +'%Y') % 4 )) -eq 0 ]] ; then
7 DAYS=366
8else
9 DAYS=365
10fi

あとは、365日もしくは366日分forで回してifで休日判定をするといった形となります。

いずれかの休日に該当したら、書き込まれるようになっているため土日かつ祝日が重なっていたとしても2重になることはありません。

1for ((i=1 ; i<=${DAYS} ; i++))do
2#1年間分回して確認する
3target_date=$(date +"%Y/%-m/%-d" --date "${i} day")

注意点

このスクリプトは実行した日から365日先の休みの日取得を行うので、クーロン(vi /etc/crontab)などで年初め1月の初旬、または3か月おき、半年おきずつに実行するのをお勧めします。

内閣府HPの祝日csvファイルの更新時期などが不明なため(2024年度分は2023年の2月に発表とのこと)定期的に回しておくのが無難かと思われます。

ちなみに自分はこのように設定しました。

100 10 1 6,12 *  root sh /home/hoge/server-taiki/holiday_check.sh

理由としては、

12月半ばに来年1月の祝日内容が必要になるのが1つ目の理由です。

2つ目は確実性を持たせるためです。

12月に実行することで来年12月までの祝日は確実に取得

6月に実行することで来年の6月までの祝日を取得

もし仮に6月になっても来年の祝日情報が更新されてなくても12月再度確認も兼ねて実行することで確実に来年12月までの祝日は取得

といった繰り返しで確実性も兼ねて設定しています。内閣府HPの祝日csvファイルの更新時期が判明すれば無駄な実行はしないのですが、不明なあたり保険をかけて数回実行している形です。

まぁ、下記のように1年に一回でも問題ないとは思います。

100 10 1 1 *  root sh /home/hoge/server-taiki/holiday_check.sh

3.後は月から金に動作してるスクリプトに追加

この休みの日の一覧を取得したseeds_holiday.csvを元に前回の記事で作成したスクリプトにif文で追記します。

1#!/bin/bash
2HOLIDAY_LIST=/home/hoge/server-taiki/holiday.csv
3if [ -z "$(grep $(date +"%Y/%-m/%-d")  $HOLIDAY_LIST)" ] ; then
4   #平日に処理する中身
5fi

試しに以下のスクリプトを使ってみました。

1#!/bin/bash
2HOLIDAY_LIST=/home/hoge/server-taiki/holiday.csv
3if [ -z "$(grep $(date +"%Y/%-m/%-d" --date "$1 day")  $HOLIDAY_LIST)" ] ; then
4   #平日に処理する中身
5   echo "平日です"
6else
7   echo "休みです"
8fi
1[root@hoge server-taiki]# date
22023112日 木曜日 16:02:57 JST
3[root@hoge server-taiki]# sh test.sh 1
4平日です
5[root@hoge server-taiki]# sh test.sh 2
6休みです

うまくいきましたね。これで祝日や夏季休暇などに動いたりする心配もなさそうです♪

これで2つあった問題のうち1つ

「スクリプトが祝日や夏季休暇、年末・年始 休暇にも動作してしまう問題」

は解決しました。

4.slackに翌月の祝日一覧を載せる

2つ目の「当月の下旬あたりにサーバー待機という翌月の土日祝にサーバー障害対応スタッフの人員を決め、月末手動で祝日一覧を出すのが面倒」の問題点を解決したいと思います。

以下のスクリプトで解決しました。

slackbotのwebhookなどの取得方法は以下を参考にしてください

参考:slack help center | Slack での Incoming Webhook の利用

1#!/bin/bash
2HOLIDAY_LIST="/home/hoge/server-taiki/holiday.csv"
3#翌月分の祝日一覧掲示
4stand_by_day=`grep "$(date +"%Y/%-m/" -d "15 days")" ${HOLIDAY_LIST}`#翌月(10日後の月を取得)
5month=`date +"%-m" -d "15 days"`result=${month}"月サーバー待機日を決めましょう。 \n \`\`\`"${stand_by_day}"\`\`\`"
6#slackにcurlで投稿
7curl -X POST -H 'Content-type: application/json' --data '{"channel": "#********", "username": "サーバー待機","text":"'"${result}"'", "icon_emoji":":server-taiki:"}' https://hooks.slack.com/services/***********************************

試しに実行してみると

このようにうまくいきました。

後はこれもクーロン(vi /etc/crontab)で以下のように設定して完成です。

100 11 23 * *  root sh /home/shell/server-taiki/server-taiki.sh

注意点

date +”%-m” -d “15 days”の”15 days”を”1 months”に設定しても良かったのですが、以下の記事が理由で辞めました。

Qiita | dateコマンドで来月1日を取得する方法

多分この23日から”1months”後は問題なく来月の月を取得してくれるはずですが、「23日の15日後なら確実に来月になっているだろう」といった理由からこのように設定しました。

クーロンでその他の日付を設定される方は”15 days”を微調整してください。

以上で、2点目の「当月の下旬あたりにサーバー待機という翌月の土日祝にサーバー障害対応スタッフの人員を決め、月末手動で祝日一覧を出すのが面倒」も解決しました。

祝日に稼働してしまう問題と手動ポチポチ問題が解決してスッキリです。

ぜひ皆さんも参考にしてみてください。