termuxでタスクログ

termuxで mariadb を利用して、リストに挙げられたタスクの実行時刻を記録するスクリプトを書いてみました。termux-dialog のような、 termuxAPI も活用しています。

まずはメインとなる親スクリプトです。

#!/bin/bash
kill `pgrep mysqld`
mysqld&
sleep 1
bin_dir=$HOME/storage/shared/bin/delivery_log
. ${bin_dir}/set_path.sh
. createDB.sh
. select_course.sh
. set_station.sh
. free_input_termux.sh
. insertDB.sh
. create_rep.sh
kill `pgrep mysqld`

mariadb の二重起動を避けるために、まず kill してからバックグラウンドで起動しなおします。mariadb はオーバーヘッドに多少時間がかかるらしく、順調に進むとエラーが出るため sleep コマンドでタイミングを取りました。

#/bin/bash
# set_path.sh パスの設定
bin_dir=$HOME/storage/shared/bin/delivery_log
report_dir=$HOME/storage/shared/Documents/配送ログ
if [ -d "${bin_dir}" ]
then
	PATH="${bin_dir}:$HOME/bin:$PATH"
fi

# その他変数の設定
host=127.0.0.1

set_path.sh で PATH を始めとする幾つかの変数を設定します。シェル変数 bin_dir にディレクトリ中に全ての実行形式が入ってますので、set_path.sh 呼び出し以後は一々ディレクトリを指定しなくても実行形式が呼び出せます。変数 report_dir は最後にログを書き出すディレクトリの名称です。

#!/bin/bash
# createDB.sh データベーステーブルの作成
# コース名
mysql -h ${host} -u user delivery << _SQL_ 
 create table if not exists t_course (
  id int primary key auto_increment,
  コース varchar(10)
  );
_SQL_

# 駅名
mysql -h ${host} -u user delivery <<_SQL_
 create table if not exists t_station (
  id int primary key auto_increment,
  コース varchar(10),
  駅名 varchar(10),
  通常順 int
);
_SQL_

# カレンダーログ
mysql -h ${host} -u user delivery <<_SQL_
 create table if not exists t_log_convenient(
  id int primary key auto_increment,
  日付 date unique,
  コース varchar(10)
);
_SQL_

# 詳細ログ
mysql -h ${host} -u user delivery <<_SQL_
 create table if not exists t_log (
  id int primary key auto_increment,
  日付 date,
  駅名 varchar(10),
  時刻 time,
  東経 double,
  北緯 double,
  メモ varchar(100)
);
_SQL_

# 当日既に登録された駅名のビューを作成
mysql -h ${host} -u user delivery <<_SQL_
 create view if not exists v_通過済 as select 駅名 from t_log where 日付=date(now());
_SQL_

# 当日のコースに含まれる駅名のビューを作成(通常順0は大阪駅なので排除)
mysql -h ${host} -u user delivery <<_SQL_
create view if not exists v_コース as 
 select 駅名,通常順 from t_station s
 join 
 (select コース from t_log_convenient 
   where 日付=date(now())) t 
 on s.コース=t.コース where 通常順>0;
_SQL_

データベースを作成します。もちろん、1回作成してしまえば必要ありませんので、SQL文中の if not exists に従って何もせずに外へ出ます。

#!/bin/bash
# select_course.sh コースを選択します
today=`\ mysql -h ${host} -u user delivery -N << _SQL_ select * from t_log_convenient where 日付=date(now()); _SQL_` # 当日のコースが決まっていなければ if [ -z "${today}" ] then #### 本日のコースを設定します #### declare -a course_a=(`\ mysql -h ${host} -u user delivery -N << _SQL_ select コース from t_course; _SQL_` ) value=`echo ${course_a[*]} | sed -e "s/ /,/g"` line=`\ termux-dialog spinner -t "本日のコースを選択してください" -v "${value}" |\ tr "\n" " "` code=`echo ${line} | jq -r .code` if [ ${code} -eq -2 ]; then exit; fi course=`echo ${line} | jq -r .text` mysql -h ${host} -u user delivery << _SQL_ insert into t_log_convenient(日付,コース) values(date(now()), "${course}") on duplicate key update コース="${course}"; _SQL_ kill `pgrep mysqld` exit fi

既に当日のコースが決まっていれば変数 ${today} に値が入りますので、何もせずに外へ出ます。もし、値が無ければ if 文中でリストボックスダイアログを起動し当日のコースを t_course テーブル中から選択します。その結果は t_log_convenient テーブルに挿入されます。3つ目のSQL中、 on duplicate key 文で再挿入ではなく更新を掛けるように設定していますが、変数 ${today} に値が入りますから、このSQLに辿り着くことは無いでしょう。必ず mariadb を停止してから exit 文で親スクリプトごと終了します。

#!/bin/bash
### set_station.sh 通常順が最も若い駅名を返します ###
station=`\
mysql -h ${host} -u user delivery -N << _SQL_ 
 select c.駅名 from v_コース c left join v_通過済 p on c.駅名=p.駅名 
   where p.駅名 is null order by c.通常順 limit 1;
_SQL_`
if [ -z ${station} ]
then
 kill `pgrep mysqld`; exit
fi

テーブル t_log_convenient に当日のレコードが挿入されている、すなわち既に当日のコースが決まっていれば、このスクリプトにやってきます。既に訪れた駅はビュー v_通過済 に駅名が登録されますから、それ以外の駅名でかつ通常順が最も若い駅名が変数 ${statiaon} に返されます。ビュー v_コース に挙げられた駅を全て通過していた場合は、該当するレコードが存在しませんから、${station} に値は入りません。そのため mariadb をkillして親スクリプトごと終了します。

#!/bin/bash
line=`\
  termux-dialog text -t "${station}駅" -i "メモを自由に入力して下さい" |\
  tr "\n" " "`
code=`echo ${line} | jq -r .code`
if [ ${code} -eq -1 ]
then
 input=`echo ${line} | jq -r .text`
else
 kill `pgrep mysqld`
 exit
fi

テキストダイアログを起動し、メモを自由入力します。何も書かなくても構いません。このOKボタンを押した瞬間がタスク実行時刻となります。自由入力されたメモは変数 ${input} に返されます。

f:id:S_E_Hyphen:20211127153813j:plain
#!/bin/bash
# insertDB.sh テーブルにログを入力します
. time_set.sh
. location_set.sh

insertDB.sh はOKボタンが押されたときにするジョブです。location_set.sh はスマホGPS機能を使用して位置情報を取りに行くスクリプトですが、絶対必要というわけでもありませんので詳細は割愛します。

#!/bin/bash
# time_set.sh ログに駅名、日付、時刻、メモを挿入します key=`\ mysql -h ${host} -u user delivery -N << _SQL_ insert into t_log(駅名,日付,時刻,メモ) values("${station}",date(now()),time(now()),"${input}"); select last_insert_id(); _SQL_`

テーブル t_log に必要な情報を挿入します。最後に create_rep.sh で所望のディレクトリにレポートファイルを出力します。

#!/bin/bash
month=`date +"%m"`
day=`date +"%d"`
course=`\
mysql -h ${host} -u user delivery -N << _SQL_
select コース from t_log_convenient 
   where 日付=date(now());
_SQL_`
repfile=${report_dir}/${month}月${day}日${course}.html

temp=`mktemp ./XXX`
mysql -h ${host} -u user delivery -N << _SQL_ > ${temp}
 select 駅名,時刻,メモ,北緯,東経 from t_log
   where 日付=date(now());
_SQL_

cat << _HEADER_ > ${repfile}
<html>
  <head>
    <meta charset="UTF-8">
    <style type="text/css">
    h3 { margin-left:60%; font-size:16pt; font-family: serif }
    table { page-break-inside:auto; margin-left:15%; font-size:16pt}
    th { background-color: #ccc; }  
    tr { page-break-inside:avoid; page-break-after:auto } 
   </style>
  </head>
 <body>
  <table border="1px" width="70%" >
  <caption><span style="font-size: 120%;">${month}月${day}日 ${course}コースのタスク実行時刻</span></caption>
  <meta http-equiv="content-type" charset="utf-8">
  <tr>
  <th width="30%">駅名</th>
  <th width="20%">時刻</th>
  <th width="30%"> 備考</th>
  <th width="10%"> 北緯</th>
  <th width="10%"> 東経</th>
  </tr>
_HEADER_

cat ${temp} |\
 awk -F"\t" --assign line="$line" \
      '{printf "  <tr valign=\"top\">\n"} \
       {printf "  <td align=\"center\">%s</td>\n",$1} \
       {printf "  <td align=\"center\" style=\"font-size:100%;\">%s</td>\n",$2} \
       {printf "  <td align=\"left\" style=\"font-size:100%;\">%s</td>\n",$3} \
       {printf "  <td align=\"left\" style=\"font-size:60%;\">%s</td>\n",$4} \
       {printf "  <td align=\"left\" style=\"font-size:60%;\">%s</td>\n",$5} \
       {printf "  </tr>\n"}' >> ${repfile}

cat << _FOOTER_ >> ${repfile}
</table>
<h3>
以上、御報告申し上げます。<BR>
  担当者 安倍晴明<BR></h3>
</body></html>
_FOOTER_

rm ${temp}

 

11月26日 東京コースのタスク実行時刻
駅名 時刻 備考 北緯 東経
新大阪 14:54:00 出発 NULL NULL
彦根 15:33:20 備忘録を残します NULL NUL
名古屋 16:02:50 通過時刻 NULL NULL
静岡 17:25:00   NULL NULL
小田原 18:14:00 実行時刻 NULL NULL
東京 18:48:30 終了時刻 NULL NULL

 

「語学学習」考

高田大介(2016)『図書館の魔女 第3巻』(ISBN:9784062933872)より、

”もしも話したいことがあるのなら、伝えたいことがあるのなら、きっと人はその言葉を手に入れる。語るべきことを持つことは、語る言葉を持つよりもずっと初めにあって、それでいてずっと難しいことなのだ。すでに話したいことが一杯で心が騒いでいるアキームは、やがて手掛かりを得れば、堰を切ったようにその手から想いを伝えるだろう。その手話がどんなに不格好でも、あのイラムが彼の言葉を、かれの思いを読み取れない訳がない。”

f:id:S_E_Hyphen:20211123141844j:plain

ここでいう語る言葉とは手話のことですが、外国語だってきっと同じですよね。どんな勉強をするのかよりも、何を伝えたいかを大切にして学んでゆきたいと改めて思いました。

月食

今日、2021年11月19日は月食でした。月食は概ね1年に1回程度は発生する天文イベントで、格別珍しいものではありません。しかし、今日の月食のように地平線付近から欠け始めるというのは、余り経験が有りません。写真にすると、只の三日月のようにも見えかねませんが…。

f:id:S_E_Hyphen:20211119193805j:plain

 

ここまで欠けてしまうと、何だかよくわからなくなってしまいますね。

f:id:S_E_Hyphen:20211119194008j:plain

 

緯度・経度の概算距離

それぞれ、どの位なのでしょうか?経度1度の距離は地球上至るところで変化します。極付近なら、それこそ1歩で経度1度を跨ぎ超えることも不可能ではないでしょう。一方、仮に完全な球体ならば緯度1度の距離は完全に一致するはずです。実際には回転楕円体なので緯度によって微妙に異なるのですが、それでも赤道と極の間に大差はありません。

東京付近(北緯34.7度、東経140.0度)を想定し、緯度・経度それぞれ1度の距離を計算してみました。距離の計算には 緯度経度から2地点間の距離を計算する で作成した distGSI を使用しています。

f:id:S_E_Hyphen:20211112144656p:plain

経度1度は概算90km、緯度1度は概算110kmということです。すなわち、

  緯度 経度
1度 110km 90km
0.1度 11km 9km
0.01度 1.1km 900m
0.001度 110m 90m
0.0001度 11m 9m
0.00001度 1m 90cm

100分の1度の誤差が1km、100,000分の1度の誤差が1mということになります。

同様に

  緯度 経度
1度 110km 90km
1分 1.83km 1.5km
1秒 30m 25m

1分の誤差は数km、1秒の誤差は数十mの誤差に相当することとなります。

#!/bin/bash
lat0=34.7
lat1=34.7
lon0=139.5
lon1=140.5
dist=`\
./distGSI lon1=${lon0} lat1=${lat0} lon2=${lon1} lat2=${lat1} | jq -r .OutputData.geoLength`
printf "経度1度の距離:%f[m:]\n" ${dist}

lat0=34.2
lat1=35.2
lon0=140.0
lon1=140.0
dist=`\
./distGSI lon1=${lon0} lat1=${lat0} lon2=${lon1} lat2=${lat1} | jq -r .OutputData.geoLength`
printf "緯度1度の距離:%f[m:]\n" ${dist}

ちなみに高緯度(40度付近)で計算すると、経度1度の距離は約85kmになります。また緯度1度の距離は111.035kmとわずかながら長くなることがわかります。

滋賀・岐阜ドライブ

2021年11月5日【第1日】

新型コロナウィルス感染症も、ワクチン接種率の向上に伴い下火となってきました。久しぶりのドライブ旅行を楽しもうと思います。

10時にレンタカー屋で車を受け取り出発です。2年以上運転していないため少々緊張しましたが、2~3時間で慣れました。

f:id:S_E_Hyphen:20211112105609j:plain

昼食は名神高速大津SAの鰺フライ定食です。レストランから琵琶湖を望むことができます。サービスエリアの展望台よりもレストランからの眺望の方が素敵でした。

 

f:id:S_E_Hyphen:20211112105831j:plain

レンタカーはトヨタAQUAハイブリッドです。少し値が張りましたが燃料価格高騰の折り、燃費を重視しました。

 

f:id:S_E_Hyphen:20211112105932j:plain

滋賀県安土城考古博物館へ向かいました。安土城はあの織田信長の居城です。信長人気にあやかった博物館かと思いきや、付近の弥生時代の遺跡や古墳の出土物も展示した総合的な博物館でした。

 

八日市ICから岐阜羽島ICを経由して岐阜駅前のホテルへ向かいます。大浴場で温まってから近所の居酒屋でお楽しみの夕食です。食事は大変美味しかったのですが、酔っぱらっていて見栄えのする写真が皆無でした。

 

f:id:S_E_Hyphen:20211112110712j:plain

居酒屋隣のシティタワー43から撮影した岐阜駅周辺の夜景です。100万ドルとは言いませんが、結構素敵な夜景でした。

 


 

2021年11月6日【第2日】

f:id:S_E_Hyphen:20211112111316j:plain

しっかり朝風呂を楽しんだ後、バイキング形式の朝食です。透明なプラスチック蓋を被せた小鉢を何種類も準備してくれていたのが好印象でした。コロナ対策とともに全種類コンプリートしたくなる楽しい朝食でした。

 

f:id:S_E_Hyphen:20211112111635j:plain

f:id:S_E_Hyphen:20211112111418j:plain

チェックアウトを済ませたのち、内藤記念くすり博物館を見学しました。大手製薬会社「エーザイ」工場に併設された博物館と植物園です。中国の神獣「白澤」がお出迎えしてくれます。9つの目と6つの角を持つ病魔除け・旅の守り神という空想上の動物です。白澤人気パネェ!無料のわりには堪能させて頂けるスポットです。

 

f:id:S_E_Hyphen:20211112112700j:plain

東海北陸自動車道一宮木曽川ICから名神高速彦根ICまで走り近江ちゃんぽんを食しました。一番シンプルなメニューのはずなのですが、ボリュームが有り食べ応え十分です。

 

滋賀・岐阜ドライブ(令和3年11月5日から6日) の費用総括
適用 金額 備考
宿泊費 12,450 駐車場・入湯税込み
レンタカー代 19,856  
安土城考古博物館 900  
鰺フライ定食 1,000  
居酒屋ねずみ小僧 4,202 1時間飲み放題利用
ちゃんぽん亭総本家 870  
レギュラーガソリン 2,802 16.48リットル@170円
高速道路料金 9,440  
その他駐車場代 420  
合計 51,940  

 

これからは少し日帰りドライブや国内旅行を増やしたいなと思った旅でした。

シェル変数の引継ぎを確認する

bash で親プロセスから子プロセスへ適切に変数が引き継がれているか確認したい場合があります。一々if文で判定を行っていたのですが、ループを使用して行数を大幅に減らせることがわかりました。${!var} という表記がミソです。${var} に fuga という値が代入されると、 ${!var} は ${fuga} を評価することになります。すなわち [ -z ${!var} ] は ${fuga} に値が入っているか否かを判定していることになります。

#!/bin/bash
error_num=0
for var in fuga hoge
do
 if [ -z ${!var} ]
  then
   printf "[%s] 関数 %s の変数 ${var} に値がありません\n" \
    "`date +"%F %T"`" `basename $0`
   error_num=`expr ${error_num} + 1`
 fi
done

echo エラーは${error_num}回です    

f:id:S_E_Hyphen:20211103162705p:plain

当初、変数 fuga にも hoge にも値が入っていませんから、そのようにエラーメッセージが表示されます。次に export を使用してfugaに値を入れてやると、エラーメッセージからfugaに関する内容が消えました。

export を使わずに変数を作成しても子プロセスには引き継がれませんからhogeのエラーは消えません。変数 error_num にはエラーの回数が積算されていますから、これを利用して強制終了させたりすることも可能となります。

28ヶ月半のタダ働き

図は財務省「財政に関する資料」(URL: https://www.mof.go.jp/tax_policy/summary/condition/a02.htm ) から引用した債務残高の国際比較(対GDP比)です。2020年、日本の債務残高は240%に到達しようとしています。

f:id:S_E_Hyphen:20211030161135g:plain

国債の発行残高が令和2年度で950兆円、20年1-12期GDPが538兆円です。おそらく債務残高には地方債の発行残高も含まれるでしょうから、概ね2倍ということなら間違いないと思います。

20年のGDPはコロナ禍で減少しているとはいうものの、コロナの影響を受けていない19年のGDPでも560兆円足らずですから、劇的な回復は期待できません。240%ということは即ち、日本人全員が28.5ヶ月間タダ働きして漸く返済できる借金を背負っているということになります。

明日、令和3年10月31日は第49回衆議院議員総選挙です。コロナ対策や経済対策が大きな争点として取り上げられているようです。もちろん真剣に取り組んでいただきたい課題ではあります。しかし、財政健全化も疎かにならないよう、注目して一票を投じたいものです。