概要
定期実行するコマンドに、dateコマンドで得た文字列を渡したい。
というのを、crontabでは特に問題なくできていたが、
systemd.timer で同じことをやろうとすると少々はまったという話。
本記事における前提
スクリプトへの引数として、「先月の1日」のYYYYMMDD文字列を渡す、とします
1. シェル
まずシェルで、dateコマンドで先月1日を得る方法。
# 本体
date "+%Y%m%d" --date "$(date '+%Y%m01') 1 month ago"
# 確認用
$ sudo date -s '20250331'; date "+%Y%m%d" --date "$(date '+%Y%m01') 1 month ago"; date
Mon Mar 31 12:00:00 AM JST 2025
20250201
Mon Mar 31 12:00:00 AM JST 2025
$
2. crontab
crontabでの方法も対比として記載します。
* * * * * /vagrant/test.sh -d $(date "+\%Y\%m\%d" --date "$(date '+\%Y\%m01') 1 month ago")
%を¥でエスケープ
2025-03-08T10:09:01.129375+09:00 vm017 CRON[6853]: (vagrant) CMD (/vagrant/test.sh -d $(date "+%Y%m%d" --date "$(date '+%Y%m01') 1 month ago") )
コマンドが通りました
echo "[$(date '+%Y%m%d')] \$@: $@" >> test.log
[2025-03-07 22:11:01] $@: -d 20250301
出力されました
3. service
本命、serviceの場合。
[Unit]
Description="test.sh"
[Service]
User=vagrant
ExecStart=/bin/sh -c '/vagrant/test.sh -d $(date '+%%Y%%m%%d' -d "$(date '+%%Y%%m01') 1 month ago")'
/bin/sh -c
の引数として渡すことで$()が使えるようにして、
%を重ねることでエスケープ
sudo systemctl start test.service
[2025-03-07 22:18:24] $@: -d 20250201
期待通りの結果となりました。
完全に裏取りできたわけではないのですが、とりあえず動いたぞと。
参考サイト
コウモリのちょーおんぱ:systemd unit fileでは%のエスケープが必要
https://komorinfo.com/blog/systemd-unit-file-escape/
man/lastest/systemd.unit
https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html
stackoverflow:systemd からのサービス起動時にHOME環境変数を設定したい(/bin/sh -c じゃないとだめという情報)
https://ja.stackoverflow.com/questions/62360/