systemdは失敗した記憶しかない。
やりたいこと
PC起動時に自動でニュース取得スクリプトを実行させたい。
方法
起動時や定時などのタイミングで何かを行うにはOS固有のしくみを使うことになると思われる。スケジューラと呼ばれたりもする?
Linux(Debian9(Raspbian stretch))ではいくつかのしくみがある。※ このうちsystemdが推奨。
コード
実行するスクリプト
以下、前回のコードを実行する。
これに加えて、それを実行するためのBashスクリプトを用意する。
get_news.sh
#!/bin/bash run() { GetFeeds() { local SCRIPT_DIR="$(cd $(dirname $0); pwd)"; cat "$SCRIPT_DIR/feeds.txt"; } MakeWorkDir() { local work_dir=/tmp/work; mkdir -p "$work_dir"; cd "$work_dir"; }; MakeWorkDir; echo "PC起動時に実行したよ。: $(pwd)" > "systemd_run.txt" local run_sh="/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/run.sh" echo "$(GetFeeds)" | "$run_sh" } run exit 0
feeds.txtはフィードURLを改行区切りにしたテキストファイル。
権限付与とシバング
chmod 755 get_news.sh chmod 755 get_news.py
シバング | 拡張子 |
---|---|
#!/bin/bash |
.sh |
#!/usr/bin/env python3 |
.py |
権限付与とシバングがないせいでsystemdエラーになることがよくあるらしい。
環境
systemdで実行するとき、Pythonのパッケージをルート権限でインストールしていないと怒られるらしい。※
そこで、以下のようにルート権限で必要なパッケージをインストールした。
sudo -H pip3 install pytz sudo -H pip3 install tzlocal sudo -H pip3 install selenium sudo -H pip3 install beautifulsoup4 sudo -H pip3 install lxml sudo -H pip3 install readability-lxml sudo -H pip3 install html2text
同じパッケージを2つもインストールとか、完全にディスクの無駄遣いだろ……。
systemd
サービス作成。
/etc/systemd/system/get_news.service
[Unit] Description=ニュースを取得する。 After=local-fs.target network-online.target Requires=local-fs.target network-online.target [Service] EnvironmentFile=/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/env.txt ExecStart=/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh Restart=always Type=simple [Install] WantedBy=multi-user.target
[Service]User=???
キーがある。これを使えばルート権限でのパッケージ入手は不要? だったらいいな。
キー | 意味 |
---|---|
Unit.After | このサービスは指定したサービスの後で起動する |
Unit.Requires | このサービスは指定したサービスが必須でありそれの起動が失敗すればこれも失敗する |
Service.EnvironmentFile | 環境変数を設定したファイルパスを指定する |
Service.ExecStart | サービス起動したときに実行するコマンド |
Service.Restart | サービスプロセス停止時の再起動条件(no ,always ,...) |
Service.Type | 実行コマンドとメインプロセスの関係(simple ,forking ,oneshot ) |
Install.WantedBy | enable 時に指定したUnitの.wants ディレクトリにリンクを作る |
env.txtは、PATH=...
のように環境変数を設定したコードがかかれたファイル。
systemctl enable get_news systemctl start get_news systemctl status get_news
start
すると、なぜか認証ダイアログが出てシステムログイン認証? を求められた。3回も。間違うと怒られる。
Failed to start get_news.service: Access denied See system logs and 'systemctl status get_news.service' for details.
status
をみるとstatus=203/EXEC
エラー。
● get_news.service - ニュースを取得する。 Loaded: loaded (/etc/systemd/system/get_news.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Fri 2019-09-27 21:06:11 JST; 11h ago Process: 498 ExecStart=/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh (code=exited, status=203/EXEC) Main PID: 498 (code=exited, status=203/EXEC) 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'. 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Service hold-off time over, scheduling restart. 9月 27 21:06:11 raspberrypi systemd[1]: Stopped ニュースを取得する。. 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Start request repeated too quickly. 9月 27 21:06:11 raspberrypi systemd[1]: Failed to start ニュースを取得する。. 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Unit entered failed state. 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'.
ログを見てもよくわからん。上記以上の情報が見つからない。
/var/log/syslog
Sep 27 21:06:10 raspberrypi systemd[1]: Started ニュースを取得する。. Sep 27 21:06:10 raspberrypi systemd[1]: Starting /etc/rc.local Compatibility... Sep 27 21:06:10 raspberrypi systemd[1]: Starting Daily apt download activities... Sep 27 21:06:10 raspberrypi systemd[468]: get_news.service: Failed at step EXEC spawning /home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh: Exec format error Sep 27 21:06:10 raspberrypi systemd[1]: Started Permit User Sessions. Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Main process exited, code=exited, status=203/EXEC Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Unit entered failed state. Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'. ... Sep 27 21:06:10 raspberrypi systemd[1]: Starting Hold until boot process finishes up... Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Service hold-off time over, scheduling restart. Sep 27 21:06:10 raspberrypi systemd[1]: Stopped ニュースを取得する。.
/var/log/deamon.log
Sep 27 21:06:10 raspberrypi systemd[468]: get_news.service: Failed at step EXEC spawning /home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh: Exec format error Sep 27 21:06:10 raspberrypi systemd[1]: Started Permit User Sessions. Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Main process exited, code=exited, status=203/EXEC Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Unit entered failed state. Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'. Sep 27 21:06:10 raspberrypi systemd[1]: Starting Light Display Manager... Sep 27 21:06:10 raspberrypi systemd[1]: Started /etc/rc.local Compatibility. Sep 27 21:06:10 raspberrypi systemd[1]: Starting Terminate Plymouth Boot Screen... Sep 27 21:06:10 raspberrypi systemd[1]: Starting Hold until boot process finishes up... Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Service hold-off time over, scheduling restart. Sep 27 21:06:10 raspberrypi systemd[1]: Stopped ニュースを取得する。.
所感
動かん……。原因不明。簡単なPythonスクリプトだけなら動かせたのだが……。
なんというか、Windowsのスタートアップみたいに、ショートカット登録するだけで実行できたりしないの? OSブートの仕組みを少しは理解していないと設定できないとか、難解すぎるだろ。そんなの知らなくても自動実行したいんだよ!
情報源
- https://wiki.archlinux.jp/index.php/Systemd
- http://enakai00.hatenablog.com/entry/20130917/1379374797
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13 ※
- bash 4.4.12(1)-release ※
- Python 3.5.3
- SQLite 3.29.0 ※
- MeCab 0.996ユーザ辞書
$ uname -a Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux