前の記事では、systemd で自分のスクリプトをサービスにして、自動起動させました。今回は、systemd のもう1つの機能、systemd timer(タイマー)を使って「決まった時間に動かす」を試します。
私は毎朝のレポート作りを cron で動かしていましたが、ある日レポートが届いていませんでした。調べようとしても、cron は「動いたのか」「失敗したのか」がわかりにくく、ログを探すだけで時間がかかりました。systemd timer に変えてからは、systemctl list-timers で「次はいつ動くか」、journalctl で「前回どうだったか」がすぐ見られるようになりました。
この記事では、1分ごとに動く練習用のタイマーを作り、cron とのちがいと使い分けを整理します。
- systemd timer と cron のちがい
- タイマーが「.service」と「.timer」の2つのファイルでできている理由
-
OnCalendar=の書き方と、systemd-analyze calendarでの確かめ方 -
systemctl list-timersで、次に動く時刻を見る方法 - 電源が切れていた間の分を取り戻す
Persistent=true
-
.serviceファイルを書いて、systemctl start・enableを使える -
crontab -eで cron を設定したことがある(「毎朝の作業をPCを触らず動かしたい|cron入門(Pythonを定時実行)」の記事) -
journalctl -u 名前でログを見たことがある
まだの方は、前の記事「Linuxのsystemd入門|systemctlでサービスを起動・自動起動する【初心者向け】」から読むのがおすすめです。
- Webhook:何かが起きたときに、決めた URL へ自動で知らせを送るしくみ
- サービス:systemd が管理する、裏でずっと動いて仕事を受け付けるプログラム(デーモン)。例:
ssh.service - cron:決まった日時に、コマンドをくり返し自動で実行してくれるしくみ。裏で動く cron デーモンが、crontab に書いた予定を見て動かします
- journalctl:systemd が集めたログを見るコマンド
用語で迷ったら、連載のまとめ記事の「よく出てくる用語ミニ辞典」でも確かめられます。
結論:かんたんなら cron、見える化したいなら timer
| くらべるところ | cron | systemd timer |
|---|---|---|
| 設定の手軽さ | 1行で書ける | ファイルが2つ必要 |
| 次に動く時刻の確認 | 自分で計算する | systemctl list-timers で見られる |
| 実行結果のログ | 自分でファイルに書き出す | journalctl に自動で残る |
| 電源が切れていた間の分 | 実行されない | Persistent=true で、起動後に1回動く |
| 手で1回だけ動かす | コマンドを自分で打つ | systemctl start 名前.service |
| 向いている場面 | 自分のパソコン・かんたんな定期実行 | サーバー・失敗に気づきたい定期実行 |
準備:練習用のスクリプトを作る
- 1
- 2
- 3
mkdir -p ~/linux-practice/timer-test
cd ~/linux-practice/timer-test
nano report.sh次の内容を書いて保存します。実行するたびに、時刻を report.log に1行足すスクリプトです。
- 1
- 2
- 3
#!/bin/bash
echo "レポートを作りました: $(date '+%Y-%m-%d %H:%M:%S')" >> /home/kaito/linux-practice/timer-test/report.log
echo "kaito-report: 実行しました"- 1
- 2
- 3
chmod +x report.sh
./report.sh
cat report.logここから先の出力例は、Debian 13での実行例です(ユーザー名 kaito・パソコン名 demo のダミー環境)。UbuntuやWSL(=Windows の中で Linux を動かせる、Microsoft のしくみ)では、表示が少し違うことがあります。
(例)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
kaito@demo:~/linux-practice$ mkdir -p ~/linux-practice/timer-test
kaito@demo:~/linux-practice$ cd ~/linux-practice/timer-test
kaito@demo:~/linux-practice/timer-test$ nano report.sh
kaito@demo:~/linux-practice/timer-test$ chmod +x report.sh
kaito@demo:~/linux-practice/timer-test$ ./report.sh
kaito-report: 実行しました
kaito@demo:~/linux-practice/timer-test$ cat report.log
レポートを作りました: 2026-11-01 03:44:21画面に出るのは2行目の echo だけで、1行目の内容は report.log に書き込まれています。
まず手で動かして、スクリプトが正しく動くことを確かめておくのが大切です。
STEP 1:.service ファイルを作る(何をするか)
タイマーは「いつ」、サービスは「何を」を受け持ちます。まず「何を」から書きます。
- 1
sudo nano /etc/systemd/system/kaito-report.service- 1
- 2
- 3
- 4
- 5
- 6
- 7
[Unit]
Description=kaito の練習用レポート
[Service]
Type=oneshot
User=kaito
ExecStart=/home/kaito/linux-practice/timer-test/report.shType=oneshot は「1回動いて終わる」という意味です。前の記事のサービスのように、ずっと動き続けるものではありません。[Install] は書きません(自動起動するのはタイマーのほうだからです)。
- 1
- 2
- 3
sudo systemctl daemon-reload
sudo systemctl start kaito-report.service
cat ~/linux-practice/timer-test/report.log(例)
- 1
- 2
- 3
- 4
- 5
kaito@demo:~/linux-practice/timer-test$ sudo systemctl daemon-reload
kaito@demo:~/linux-practice/timer-test$ sudo systemctl start kaito-report.service
kaito@demo:~/linux-practice/timer-test$ cat ~/linux-practice/timer-test/report.log
レポートを作りました: 2026-11-01 03:44:21
レポートを作りました: 2026-11-01 03:44:34systemctl start で動かした分の1行が増えて、2行になりました。
手で1回だけ動かせるのが、systemd timer の便利なところです。「cron で動かすとうまくいかない」を調べるときにも役立ちます。
STEP 2:.timer ファイルを作る(いつ動かすか)
サービスと同じ名前で、拡張子(=ファイル名の最後の .txt や .py の部分)だけ .timer にしたファイルを作ります。同じ名前どうしが自動で結びつきます。
- 1
sudo nano /etc/systemd/system/kaito-report.timer- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
[Unit]
Description=kaito の練習用レポートを毎分動かす
[Timer]
OnCalendar=*-*-* *:*:00
AccuracySec=1s
Persistent=true
[Install]
WantedBy=timers.target| 書く場所 | 意味 |
|---|---|
OnCalendar=*-*-* *:*:00 | 毎日・毎時・毎分の0秒に動かす |
AccuracySec=1s | 時刻のずれを1秒以内にする(ふだんは書かなくてよい) |
Persistent=true | 電源が切れていて動けなかった分を、起動後に1回動かす |
WantedBy=timers.target | enable したとき、タイマーの仲間に加える |
STEP 3:OnCalendar の書き方を確かめる
systemd-analyze calendar を使うと、書いた時刻が「次はいつになるか」を、タイマーを動かす前に確かめられます。
- 1
- 2
- 3
systemd-analyze calendar "*-*-* *:*:00"
systemd-analyze calendar "*-*-* 07:00:00"
systemd-analyze calendar "Mon..Fri 09:30"(例)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
kaito@demo:~/linux-practice/timer-test$ systemd-analyze calendar "*-*-* *:*:00"
Normalized form: *-*-* *:*:00
Next elapse: Sun 2026-11-01 03:45:00 JST
(in UTC): Sat 2026-10-31 18:45:00 UTC
From now: 13s left
kaito@demo:~/linux-practice/timer-test$ systemd-analyze calendar "*-*-* 07:00:00"
Normalized form: *-*-* 07:00:00
Next elapse: Sun 2026-11-01 07:00:00 JST
(in UTC): Sat 2026-10-31 22:00:00 UTC
From now: 3h 15min left
kaito@demo:~/linux-practice/timer-test$ systemd-analyze calendar "Mon..Fri 09:30"
Original form: Mon..Fri 09:30
Normalized form: Mon..Fri *-*-* 09:30:00
Next elapse: Mon 2026-11-02 09:30:00 JST
(in UTC): Mon 2026-11-02 00:30:00 UTC
From now: 1 day 5h leftNext elapse が次に動く日時、(in UTC) が同じ日時を世界標準時で書いたもの、From now がそれまでの残り時間です。Original form(書いたとおりの形)は、Mon..Fri 09:30 のように、書いた形と Normalized form(systemd が読み取った正式な形)がちがうときだけ表示されます。日時は、検証したとき(11月1日の3時44分ごろ)から見た値です。
| やりたいこと | OnCalendar の書き方 | cron で書くと |
|---|---|---|
| 毎朝7時 | *-*-* 07:00:00 | 0 7 * * * |
| 平日の9時30分 | Mon..Fri 09:30 | 30 9 * * 1-5 |
| 1時間ごと | hourly | 0 * * * * |
| 毎月1日の0時 | monthly | 0 0 1 * * |
-
Persistent=trueが動く場面:「電源が切れていた」だけでなく、パソコンを止めていて(タイマーが動いていなくて)予定の時刻を過ぎた場合に、次に起動したとき1回だけ動きます。何回分を飛ばしても、動くのは1回です。ノートパソコンのスリープ中や、WSL を閉じていたあいだの扱いは、環境により異なります。毎朝7時の作業が「朝はパソコンを閉じていた日」も動いてほしいときに便利です。 -
RandomizedDelaySec=:RandomizedDelaySec=10minのように書くと、決めた時刻から最大10分のあいだで、毎回ランダムに少し遅らせて動きます。外の API(=プログラム同士がデータをやりとりするための窓口)やサイトに取りにいく作業を、ちょうど0分に集中させないための設定です(Lv3 の curl の記事で、相手のサーバーに負担をかけない話をしました)。
書いたあとは、STEP 4 の systemctl list-timers で、次に動く時刻を確かめましょう。
STEP 4:タイマーを動かす
タイマーを読み込んで、enable --now で「今から動かす&次の起動からも動かす」にします。
- 1
- 2
- 3
sudo systemctl daemon-reload
sudo systemctl enable --now kaito-report.timer
systemctl list-timers kaito-report.timer --no-pager(例)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
kaito@demo:~/linux-practice/timer-test$ sudo systemctl daemon-reload
kaito@demo:~/linux-practice/timer-test$ sudo systemctl enable --now kaito-report.timer
Created symlink '/etc/systemd/system/timers.target.wants/kaito-report.timer' → '/etc/systemd/system/kaito-report.timer'.
kaito@demo:~/linux-practice/timer-test$ systemctl list-timers kaito-report.timer --no-pager
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sun 2026-11-01 03:45:00 JST 5s - - kaito-report.timer kaito-report.service
1 timers listed.
Pass --all to see loaded but inactive timers, too.検証したときはまだ1回も動いていなかったので、LAST(前回)と PASSED(前回からの時間)は - になっています。最後の Pass --all … は、「止まっているタイマーも見たいときは --all をつけてね」という意味です。
NEXT が次に動く時刻、LEFT がそれまでの残り時間です。2〜3分待ってから、結果を確かめましょう。
- 1
- 2
cat ~/linux-practice/timer-test/report.log
journalctl -u kaito-report.service -n 10 --no-pager(例)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
kaito@demo:~/linux-practice/timer-test$ cat ~/linux-practice/timer-test/report.log
レポートを作りました: 2026-11-01 03:44:21
レポートを作りました: 2026-11-01 03:44:34
レポートを作りました: 2026-11-01 03:45:00
レポートを作りました: 2026-11-01 03:46:00
レポートを作りました: 2026-11-01 03:47:00
kaito@demo:~/linux-practice/timer-test$ journalctl -u kaito-report.service -n 10 --no-pager
Hint: You are currently not seeing messages from other users and the system.
Users in groups 'adm', 'systemd-journal' can see all messages.
Pass -q to turn off this notice.
Nov 01 03:44:34 demo report.sh[2039]: kaito-report: 実行しました
Nov 01 03:45:00 demo report.sh[2108]: kaito-report: 実行しました
Nov 01 03:46:00 demo report.sh[2115]: kaito-report: 実行しました
Nov 01 03:47:00 demo report.sh[2118]: kaito-report: 実行しましたreport.log には、手で動かした2行のあとに、03:45:00・03:46:00・03:47:00 と毎分0秒ちょうどに行が増えています。
journalctl の最初の3行の Hint は、前の記事で説明した「ほかのユーザーやシステムのログは見えていません」という注意です。そのため、一般ユーザーの kaito には、スクリプトが表示した kaito-report: 実行しました の行だけが見えています。systemd 自身が書く Starting kaito-report.service… や Finished kaito-report.service … の行は、一般ユーザーには表示されません(Hint にあるとおり、adm や systemd-journal グループのユーザーなら見られます)。
cron の記事では、cron が失敗しても何も教えてくれないので、ログを自分でファイルに書き出しました。systemd timer では、スクリプトがエラーの終了コード(0 以外)で終わると、サービスが failed(失敗)の状態になって残ります。
-
systemctl status kaito-report.service --no-pagerで、前回の結果(Active:の行)と、最後のログの数行を見られます。 -
systemctl --failedで、失敗したままのサービスの一覧を見られます。何も並ばなければ、失敗はありません。 -
systemctl list-timers --allで、止まっているタイマーも含めて、前回(LAST)と次回(NEXT)の時刻を見られます。「タイマーが動いていない」と思ったら、まずここを見ます。
慣れてきたら、.service の [Unit] に OnFailure= を書いて、失敗したときに別のサービス(通知を送るものなど)を動かすこともできます。
cron から systemd timer に乗りかえるときは、crontab -e で古い行を消すか、行の先頭に # をつけて止めてから、タイマーを有効にしてください。両方残っていると、同じメールが2通届いたり、同じファイルに二重に書き込んだりします。今の cron の設定は crontab -l で確かめられます。
この記事の「毎分」は、すぐに結果を見るための練習用です。本物のタイマーで、メールの送信や外部の API の呼び出し、大きなファイルのコピーを毎分動かすと、相手のサービスに迷惑をかけたり、ディスク(=データをしまっておく部品)がいっぱいになったりします。練習が終わったら、必ず後片づけで止めましょう。
🤖 詰まったらAIに聞こう:cron の設定を timer に書きかえたい
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Linuxの初心者です。cronで動かしている定期実行を、systemd timerに書きかえたいです。
.serviceと.timerの2つのファイルの中身と、有効にする手順、
動いたかを確かめる方法を教えてください。
【今のcrontabの行】例:0 7 * * * /home/kaito/scripts/report.sh
【動かすユーザー】例:kaito
【やりたいこと】例:毎朝7時に動かしたい。PCが止まっていた日は起動後に1回動かしたい
【使っているOS】例:Debian 13 / Ubuntu 24.04crontab やスクリプトに、API キー・パスワード・Webhook の URLを直接書いていることがあります。貼る前に「***」に置き換えてください。ユーザー名やパスも、気になる場合は「kaito」などに置き換えましょう。
後片づけ
タイマーを止めて、2つのファイルを消し、読み直します。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
sudo systemctl disable --now kaito-report.timer
sudo rm /etc/systemd/system/kaito-report.timer /etc/systemd/system/kaito-report.service
sudo systemctl daemon-reload
systemctl list-timers --all --no-pager | grep kaito
cd ~/linux-practice
rm -r timer-test
ls(例)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
kaito@demo:~/linux-practice/timer-test$ sudo systemctl disable --now kaito-report.timer
Removed '/etc/systemd/system/timers.target.wants/kaito-report.timer'.
kaito@demo:~/linux-practice/timer-test$ sudo rm /etc/systemd/system/kaito-report.timer /etc/systemd/system/kaito-report.service
kaito@demo:~/linux-practice/timer-test$ sudo systemctl daemon-reload
kaito@demo:~/linux-practice/timer-test$ systemctl list-timers --all --no-pager | grep kaito
kaito@demo:~/linux-practice/timer-test$ cd ~/linux-practice
kaito@demo:~/linux-practice$ rm -r timer-test
kaito@demo:~/linux-practice$ ls
archive-test chmod-test edit-test find-test grep-test link-test perm-test redirect-testよくある質問
Q. タイマーを作ったのに、list-timers に出てきません。
enable --now を忘れているか、.timer を作ったあとの daemon-reload を忘れていることが多いです。systemctl list-timers --all で止まっているタイマーも表示し、systemctl status kaito-report.timer で Loaded: と Active: を確かめましょう。.timer と .service の名前(拡張子の前)がちがうと、結びつきません。
Q. cron とタイマーのどちらを使えばいいか、迷います。
自分のパソコンで「毎朝なにかを動かす」くらいなら、1行で書ける cron(Lv3 の cron 入門の記事)で十分です。サーバーで動かす作業や、失敗に気づきたい作業、止まっていた日の分も動かしたい作業は、タイマーが向いています。どちらにしても、同じ作業を両方に書かないようにしましょう。
Q. タイマーで動かすスクリプトに、API キーを使いたいです。
前の記事(systemd 入門)の Python の箱と同じく、.service の [Service] に EnvironmentFile= で .env(=APIキーなどの秘密の設定を書いておくファイル)を読みこむ形にします。API キーを .service や .timer に直接書かないでください。
まとめ
- systemd timer は「.timer(いつ)」と「.service(何を)」の2つのファイルで動く。名前をそろえる
- 1回で終わる作業は
Type=oneshot。手で1回だけ動かすならsystemctl start 名前.service - 時刻は
OnCalendar=で書き、systemd-analyze calendarで事前に確かめる -
systemctl list-timersで次の実行時刻、journalctl -uで結果が見られる -
Persistent=trueで、電源が切れていた間の分を起動後に取り戻せる - かんたんなら cron、サーバーで失敗に気づきたいなら timer。二重に動かさない
次の記事では、今回も使った journalctl を中心に、Linux のログの見方を学びます。「動かない」「止まった」ときに、原因を探す方法です。
次に読む記事
- 前の記事:Linuxのsystemd入門|systemctlでサービスを起動・自動起動する【初心者向け】
- 次の記事:Linuxのログの見方|journalctlと/var/logでエラーの原因を探す【初心者向け】
関連する記事
- Pythonで毎朝のCSV集計を自動化する(pandas+定期実行):タイマーで毎朝動かしたい Python のスクリプトを作りたい方に
- Pythonで毎日の作業を自動化する入門|ダウンロードフォルダを自動で整理しよう:定期実行に向いた、身近な自動化を探している方に
- n8nとは?最初のワークフローを1本つくる:画面で定期実行を組み立てる方法もくらべたい方に