毎朝の作業をPCを触らず動かしたい|cron入門(Pythonを定時実行)

Pythonで自動化スクリプトは書けた。でも、毎朝ターミナルを開いて python daily_job.py と打つのは、結局自分の手……。そんなところで止まっていませんか?

私も、スクリプトが動いたことに満足して、毎朝手で実行していた時期があります。忙しい日にうっかり忘れると、「自動化したはずの作業」がそのまま溜まってしまうんですよね。

この記事では、Linuxの定時実行の仕組み cron(クーロン) を使って、Pythonのスクリプトを決まった時刻に自動で動かす流れを、一緒にやってみましょう。つまずきやすい「パス(=ファイルやディレクトリの場所を表す「住所」の書き方)」と「ログ」も、Debian 13 の cron で実際に動かして確かめた結果をもとにまとめます。

💡
この記事でわかること
  • cronとは何か(GASの時間主導型トリガーとの違い)
  • crontab -e での書き方と、5つの時刻フィールド
  • 絶対パス(=いちばん上の / から書いた場所)と、仮想環境(venv)のPythonの指定のしかた
  • ログ(=プログラムが残す「いつ、何が起きたか」の記録)の残し方(>> ログ 2>&1)と、cron自体の記録の見方(journalctl)
  • ジョブの止め方(# で一時停止・行を消す)
  • 動かないときの確認ポイントと、WSLで使うときの注意点
🔰
この記事の前提
  • 前の記事で、~/linux-practice/python-test に venv と hello.py を作ってある
  • nano でファイルを書いて保存できる
  • >> で出力をファイルに追記できる

まだの方は、前の記事「LinuxでPythonを動かす|apt・venv・pipの手順【初心者向け】」から読むのがおすすめです。この記事のパスに出てくる kaito は、自分のユーザー名に読みかえてください(echo $HOME で、自分のホームのパスがわかります)。

💡
用語メモ
  • sudo:許可されたユーザーが、コマンドの前につけて、そのコマンドだけを管理者(root)の権限で実行するしくみ。パスワードを聞かれたら、root ではなく自分のパスワードを入れます
  • 標準エラー:エラーメッセージ専用の出口。ふだんは画面に出ます。番号は 2 で、2> でファイルに分けられます
  • 標準出力:コマンドのふつうの結果が出る出口(番号は 1)。ふだんは画面に出ます
  • ターミナル:文字を打ってパソコンに指示を出すための画面(アプリ)。いわゆる「黒い画面」です。打った文字を読み取って動かすのは、この中で動いている「シェル」です

用語で迷ったら、連載のまとめ記事の「よく出てくる用語ミニ辞典」でも確かめられます。


結論:crontabに「いつ・何を」を1行書けば動く

やること コマンド・書き方
crontab を開いて書く crontab -e
書いた内容を確かめる crontab -l
1行の形 分 時 日 月 曜日 コマンド
毎朝7:00に動かす 0 7 * * * の後ろに、Pythonとスクリプトを絶対パスで書く
ログを残す 行の最後に >> ログファイル 2>&1
cron自体の記録を見る sudo journalctl -u cron
一時的に止める crontab -e で行の先頭に #

この3つ(crontab -e で1行書く・絶対パス・ログ)を押さえれば、「毎朝の実行」はPCを触らなくても回り始めます。

cronの流れ

cronとは?GASの時間主導型トリガーのLinux版

cronは、Linuxなどで決まった時刻にコマンドを自動で実行してくれる仕組みです。Pythonのスクリプトも、「python コマンドを実行する」という1つのコマンドなので、cronから動かせます。

GASを使ったことがある方なら、時間主導型トリガー(「毎日午前7時〜8時に実行」のような設定)の役割と同じ、とイメージするとわかりやすいと思います。GAS側の設定手順は、GASを毎日自動で動かす|時間主導型トリガーの設定手順で整理しています。

GASの時間主導型トリガー cron
動かす対象 GASの関数 コマンド(Pythonなど)
設定の場所 GASの画面 crontab(テキストの設定)
動く場所 Googleのサーバー cronが入っているLinux環境

大きな違いは、cronでは設定を1行のテキストで書くことと、「動く環境」を自分で用意することです。


準備:cronが動いているか確かめる

練習は、前の記事で venv を作った ~/linux-practice/python-test の中で行います。まず、今の時刻と、cron が動いているかを確かめます。

  • 1
  • 2
  • 3
cd ~/linux-practice/python-test
date
systemctl status cron

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
kaito@demo:~/linux-practice/python-test$ cd ~/linux-practice/python-test
kaito@demo:~/linux-practice/python-test$ date
Sun Nov  1 05:49:41 JST 2026
kaito@demo:~/linux-practice/python-test$ systemctl status cron
● cron.service - Regular background program processing daemon
     Loaded: loaded (/usr/lib/systemd/system/cron.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-11-01 05:45:06 JST; 4min 36s ago
 Invocation: 4e3464018b9745e19386e2d90e34d4ce
       Docs: man:cron(8)
   Main PID: 131 (cron)
      Tasks: 1 (limit: 19197)
     Memory: 368K (peak: 1.7M)
        CPU: 8ms
     CGroup: /system.slice/cron.service
             └─131 /usr/sbin/cron -f

Warning: some journal files were not opened due to insufficient permissions.

Active: active (running) なら、cron は動いています。enabled は、パソコンを起動したときに自動で動き出す設定、という意味です。Debian 13 では、最初から cron が入っていて動いていました。最後の Warning: some journal files were not opened due to insufficient permissions. は、「権限が足りないので、記録の一部は表示していません」という案内で、cron の動きには関係ありません。

cron は、このパソコンの時刻(ここでは JST=日本時間)でジョブを動かします。サーバーで使うときは、date で時刻と時間帯を確かめておきましょう。


準備:毎朝動かすスクリプトを作る

cron で動かすスクリプトとして、時刻つきで「start」と「done」を出すだけの、小さな daily_job.py を作ります。ログを入れる logs フォルダも作っておきます。

  • 1
  • 2
mkdir -p logs
nano daily_job.py

nano が開いたら、次の中身を入力して、Ctrl+O → Enter で保存し、Ctrl+X で閉じます。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
import sys
from datetime import datetime

def now():
    return datetime.now().isoformat(timespec="seconds")

def main():
    print(f"{now()} start")
    # ここに本来の処理を書く(この例ではダミー)
    print(f"{now()} done")

if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print(f"{now()} ERROR: {e!r}", file=sys.stderr)
        sys.exit(1)

エラーのときは、標準エラー出力に ERROR の行を出して、終了コード(=コマンドが終わったときに返す数字)1 で終わるように書いてあります(あとの「失敗に気づく簡単な方法」で使います)。まず、手で動かしてみます。

  • 1
  • 2
mkdir -p logs
venv/bin/python daily_job.py

(例)

  • 1
  • 2
  • 3
  • 4
kaito@demo:~/linux-practice/python-test$ mkdir -p logs
kaito@demo:~/linux-practice/python-test$ venv/bin/python daily_job.py
2026-11-01T05:49:52 start
2026-11-01T05:49:52 done

「start」と「done」の2行が出れば準備完了です。


crontabの書き方:5つの時刻フィールド

cronの設定は、crontab(クーロンタブ)という、ユーザーごとの設定に書きます。書式は、「分 時 日 月 曜日 コマンド」の順です。

順番 意味 指定できる値
1つ目 分 0〜59
2つ目 時 0〜23
3つ目 日 1〜31
4つ目 月 1〜12
5つ目 曜日 0〜7(0と7は日曜日)

* は「毎回」という意味です。よく使う形を並べると、次のようになります。

  • 1
  • 2
  • 3
  • 4
  • 5
0 7 * * *       # 毎日 7:00
30 8 * * 1-5    # 平日(月〜金)の 8:30
*/10 * * * *    # 10分ごと
0 9 1 * *       # 毎月1日の 9:00
* * * * *       # 毎分

この記事で実際に動かしたのは、毎分の * * * * * と、毎日7:00の 0 7 * * * です。最初のテストは、あえて毎分にしておくと、結果がすぐ見られて安心です。うまく動くのを確認してから、0 7 * * * のように本番の時刻に直しましょう。


crontab -e で、はじめてのジョブを書く

まず、crontab -l で、今の crontab を見てみます。

  • 1
crontab -l

(例)

  • 1
  • 2
kaito@demo:~/linux-practice/python-test$ crontab -l
no crontab for kaito

no crontab for kaito は、「kaito の crontab はまだありません」という意味です。では、crontab -e で開きます。

  • 1
crontab -e

はじめて crontab -e を打つと、使うエディタを番号で選ぶ画面が出ます。

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
kaito@demo:~/linux-practice/python-test$ crontab -e
no crontab for kaito - using an empty one
Select an editor.  To change later, run select-editor again.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.tiny

Choose 1-2 [1]: 1
crontab: installing new crontab

Debian 13での実行画面

1. /bin/nano <---- easiest(いちばんかんたん)とあるので、1 を入力して Enter を押します(何も入れずに Enter でも、[1] の nano になります)。選んだエディタは覚えておいてくれるので、2回目からはこの画面は出ません。あとで変えたいときは、画面の案内どおり select-editor と打ちます。

nano が開くと、上のほうに # で始まる英語の説明が並んでいます(# で始まる行は、cronに読まれません)。上の帯に出るファイル名は /tmp/crontab.〜 のような名前ですが、これは crontab が自動で作る一時ファイルなので、気にしなくて大丈夫です。Alt+/ でいちばん下に移動して、次の4行を書きます。1行は途中で改行せず、1行のまま書きます。

  • 1
  • 2
  • 3
  • 4
* * * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/hello.py >> /home/kaito/linux-practice/python-test/cron.log 2>&1
* * * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/daily_job.py >> /home/kaito/linux-practice/python-test/logs/daily.log 2>&1
* * * * * pwd > /home/kaito/linux-practice/python-test/logs/env.log; echo "$PATH" >> /home/kaito/linux-practice/python-test/logs/env.log
* * * * * venv/bin/python hello.py >> /home/kaito/linux-practice/python-test/logs/a_relative.log 2>&1

それぞれ、こういう意味です。

  • 1行目:毎分、venv の Python で hello.py を動かし、cron.log に追記する
  • 2行目:毎分、venv の Python で daily_job.py を動かし、logs/daily.log に追記する(あとで毎朝7時に直します)
  • 3行目:毎分、cron で動いたときの作業フォルダ(pwd)と PATH(=コマンドの本体を探しにいくディレクトリを、コロン : で区切って並べた環境変数)を logs/env.log に書く(確かめ用)
  • 4行目:わざと相対パスで書いた失敗例(確かめ用)

Ctrl+O → Enter で保存して、Ctrl+X で閉じると、crontab: installing new crontab(新しい crontab を登録しました)と表示されます。これで登録は完了です。


crontab -l で、登録した内容を確かめる

  • 1
crontab -l

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
kaito@demo:~/linux-practice/python-test$ crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
…(途中省略)…
# m h  dom mon dow   command
* * * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/hello.py >> /home/kaito/linux-practice/python-test/cron.log 2>&1
* * * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/daily_job.py >> /home/kaito/linux-practice/python-test/logs/daily.log 2>&1
* * * * * pwd > /home/kaito/linux-practice/python-test/logs/env.log; echo "$PATH" >> /home/kaito/linux-practice/python-test/logs/env.log
* * * * * venv/bin/python hello.py >> /home/kaito/linux-practice/python-test/logs/a_relative.log 2>&1

Debian 13での実行画面

上の # の行は、Debian が最初から入れておいてくれる英語の説明(全部で23行)で、いちばん下の # m h dom mon dow command が「分 時 日 月 曜日 コマンド」の並びを表しています。その下に、書いた4行が入っていれば大丈夫です。

大事なジョブを書いたら、ファイルに控えておくと安心です。

  • 1
crontab -l > crontab-backup.txt

(例)

  • 1
kaito@demo:~/linux-practice/python-test$ crontab -l > crontab-backup.txt

消してしまっても、crontab crontab-backup.txt で、この控えの内容に戻せます(この記事では、戻す操作は試していません)。

🚫
crontab -r はまるごと消える(文章だけで説明します)

crontab -r は、自分のcrontabを確認なしで、まるごと消すコマンドです。キーボードでは e と r がとなりにあるので、crontab -e のつもりで打ちまちがえる事故がよく知られています。この記事では打ちません。行を消したいときは、このあと説明するように crontab -e で開いて消します。


cronで動いたか確かめる

cron は、毎分の 0秒すぎに動きます。書いてから2分ほど待って、ログを見てみます。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
date
cat cron.log
cat logs/daily.log
cat logs/env.log
cat logs/a_relative.log
grep CRON /var/log/syslog

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
kaito@demo:~/linux-practice/python-test$ date
Sun Nov  1 05:52:24 JST 2026
kaito@demo:~/linux-practice/python-test$ cat cron.log
requests を読み込めました: 2.34.2
動かした Python: /home/kaito/linux-practice/python-test/venv/bin/python
requests を読み込めました: 2.34.2
動かした Python: /home/kaito/linux-practice/python-test/venv/bin/python
kaito@demo:~/linux-practice/python-test$ cat logs/daily.log
2026-11-01T05:51:01 start
2026-11-01T05:51:01 done
2026-11-01T05:52:01 start
2026-11-01T05:52:01 done
kaito@demo:~/linux-practice/python-test$ cat logs/env.log
/home/kaito
/usr/bin:/bin
kaito@demo:~/linux-practice/python-test$ cat logs/a_relative.log
/bin/sh: 1: venv/bin/python: not found
/bin/sh: 1: venv/bin/python: not found
kaito@demo:~/linux-practice/python-test$ grep CRON /var/log/syslog
grep: /var/log/syslog: No such file or directory

Debian 13での実行画面

cron.log と logs/daily.log に、05:51 と 05:52 の2回分が追記されていました。daily.log の時刻が 05:51:01 のように :01 になっているのは、cron が分の頭(0秒)に起きて、すぐに動かしたからです。「書いた瞬間」ではなく、次の分の区切りで動く、という感覚です。

cron.log の 動かした Python: /home/kaito/linux-practice/python-test/venv/bin/python から、cron からでも venv の Python で動き、venv に入れた requests も読めたことがわかります。

最後の grep CRON /var/log/syslog は、cron の記録を探すときによく紹介される方法ですが、この Debian 13 には /var/log/syslog がありませんでした(No such file or directory)。cron の記録の見方は、あとの「cron自体の記録を見る」で説明します。


パスは「絶対パス」で書く(venvのPythonもフルパス)

cron入門で一番つまずきやすいのが、パスです。上の env.log と a_relative.log を見ると、理由がわかります。

  • env.log の1行目 /home/kaito:cron で動いたときの作業フォルダは、ホームのフォルダでした。crontab -e を打ったときにいた python-test ではありません。
  • env.log の2行目 /usr/bin:/bin:cron で動いたときの PATH は、この2つだけでした。ターミナルの PATH(echo $PATH で見られるもの)とはちがいます。
  • a_relative.log の /bin/sh: 1: venv/bin/python: not found:相対パスの4行目は、毎回この失敗でした。

4行目の venv/bin/python hello.py は、python-test にいれば動きます。でも cron は /home/kaito で動かすので、/home/kaito/venv/bin/python を探してしまい、見つかりませんでした。また、PATH が /usr/bin:/bin だけなので、自分で足した場所(~/linux-practice/bin など)にあるコマンドも、名前だけでは見つかりません。

だから、cron にはPythonも、スクリプトも、ログも、絶対パス(/ から始まるパス)で書くのが確実です。どうしても相対パスで書きたいときは、cd してから動かす方法もあります。

  • 1
  • 2
  • 3
  • 4
  • 5
# 方法1:絶対パスで書く(おすすめ)
/home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/hello.py

# 方法2:先にcdしてから動かす
cd /home/kaito/linux-practice/python-test && venv/bin/python hello.py

(方法2の形は、この記事では動かしていません。)

venv を使っているなら、Python も venv の中の bin/python をフルパスで書きます。前の記事で見たとおり、venv に入れたライブラリは、venv の Python からしか読めないからです。cron には source venv/bin/activate の手順がないので、venv の Python を直接指定するのがかんたんです。


ログを残す:>> ログファイル 2>&1

cronで動いたスクリプトは、画面に何も出ません。あとから「ちゃんと動いたかな?」を確かめるために、出力をファイルに残しておくのが大切です。

  • >> ログファイル:画面に出る内容(標準出力)を、ファイルの末尾に追記する
  • 2>&1:エラー(標準エラー出力)も、同じ場所にまとめる

上の a_relative.log に not found のエラーが残っていたのは、行の最後に 2>&1 を書いていたからです。2>&1 がないと、エラーはログファイルに入りません。

crontab の説明文にも、Output of the crontab jobs (including errors) is sent through email to the user the crontab file belongs to (unless redirected).(ジョブの出力は、エラーも含めて、ファイルに向け直さないかぎり、crontab の持ち主にメールで送られます)と書かれています。メールを送るしくみが入っていないパソコンでは、読めないままになってしまうので、>> ログ 2>&1 は必ず書いておくのが無難です。


cron自体の記録を見る(journalctl)

「ジョブがそもそも動いたのか」は、cron 自体の記録で確かめます。この Debian 13 には /var/log/syslog がないので、journalctl で見ます。

  • 1
  • 2
journalctl -u cron --no-pager
sudo journalctl -u cron --no-pager -n 16

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
kaito@demo:~/linux-practice/python-test$ journalctl -u cron --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.
-- No entries --
kaito@demo:~/linux-practice/python-test$ sudo journalctl -u cron --no-pager -n 16
[sudo] password for kaito:
Nov 01 05:51:01 demo CRON[628]: pam_unix(cron:session): session closed for user kaito
Nov 01 05:51:01 demo CRON[627]: pam_unix(cron:session): session closed for user kaito
Nov 01 05:51:01 demo CRON[629]: pam_unix(cron:session): session closed for user kaito
Nov 01 05:51:01 demo CRON[630]: pam_unix(cron:session): session closed for user kaito
Nov 01 05:52:01 demo CRON[645]: pam_unix(cron:session): session opened for user kaito(uid=1000) by kaito(uid=0)
Nov 01 05:52:01 demo CRON[642]: pam_unix(cron:session): session opened for user kaito(uid=1000) by kaito(uid=0)
Nov 01 05:52:01 demo CRON[643]: pam_unix(cron:session): session opened for user kaito(uid=1000) by kaito(uid=0)
Nov 01 05:52:01 demo CRON[644]: pam_unix(cron:session): session opened for user kaito(uid=1000) by kaito(uid=0)
Nov 01 05:52:01 demo CRON[650]: (kaito) CMD (/home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/hello.py >> /home/kaito/linux-practice/python-test/cron.log 2>&1)
Nov 01 05:52:01 demo CRON[651]: (kaito) CMD (venv/bin/python hello.py >> /home/kaito/linux-practice/python-test/logs/a_relative.log 2>&1)
Nov 01 05:52:01 demo CRON[652]: (kaito) CMD (pwd > /home/kaito/linux-practice/python-test/logs/env.log; echo "$PATH" >> /home/kaito/linux-practice/python-test/logs/env.log)
Nov 01 05:52:01 demo CRON[653]: (kaito) CMD (/home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/daily_job.py >> /home/kaito/linux-practice/python-test/logs/daily.log 2>&1)
Nov 01 05:52:01 demo CRON[642]: pam_unix(cron:session): session closed for user kaito
Nov 01 05:52:01 demo CRON[643]: pam_unix(cron:session): session closed for user kaito
Nov 01 05:52:01 demo CRON[644]: pam_unix(cron:session): session closed for user kaito
Nov 01 05:52:01 demo CRON[645]: pam_unix(cron:session): session closed for user kaito

Debian 13での実行画面

sudo なしだと、-- No entries --(記録なし)と表示されました。Hint: の行のとおり、ふつうのユーザーには、システムの記録は見せないようになっているからです。sudo をつけると、記録が見えました([sudo] password for kaito: では自分のパスワードを入れます。入力しても画面には出ません)。

  • --no-pager:画面を止めずに、まとめて表示する
  • -n 16:最後の16行だけを表示する
  • (kaito) CMD (…):kaito の crontab の、どの行を動かしたか
  • session opened / session closed:ジョブのたびに、kaito として動き始めて、終わったという記録

CMD の行があれば、cron はジョブを動かしています。それでも結果がおかしいときは、自分のログファイル(2>&1 で残したもの)を見ます。


ジョブを止める・毎朝7時に戻す・全部消す

行の先頭に # をつけて、一時的に止める

テストの hello.py の行を、消さずに止めてみます。crontab -e で開いて、Ctrl+W(検索)で hello.py >> を探し、Ctrl+A で行の先頭に移動して # を入力します。保存して閉じると、また crontab: installing new crontab と表示されます。

  • 1
crontab -e

(例)

  • 1
  • 2
kaito@demo:~/linux-practice/python-test$ crontab -e
crontab: installing new crontab

Debian 13での実行画面

nano の画面では、長い行の右はしが > で切れて見えますが、中身は1行のまま残っています。止まったかは、少し待って行数を数えて確かめます。grep -v "^# " は、「# と空白で始まる行(Debian の説明文)を表示しない」という意味で、自分で書いた行だけを見るために使っています。

  • 1
  • 2
crontab -l | grep -v "^# "
date; wc -l cron.log logs/daily.log

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
kaito@demo:~/linux-practice/python-test$ crontab -l | grep -v "^# "
#* * * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/hello.py >> /home/kaito/linux-practice/python-test/cron.log 2>&1
* * * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/daily_job.py >> /home/kaito/linux-practice/python-test/logs/daily.log 2>&1
* * * * * pwd > /home/kaito/linux-practice/python-test/logs/env.log; echo "$PATH" >> /home/kaito/linux-practice/python-test/logs/env.log
* * * * * venv/bin/python hello.py >> /home/kaito/linux-practice/python-test/logs/a_relative.log 2>&1
kaito@demo:~/linux-practice/python-test$ date; wc -l cron.log logs/daily.log
Sun Nov  1 05:52:46 JST 2026
  4 cron.log
  4 logs/daily.log
  8 total

1分ほど待ってから、もう一度数えます。

  • 1
date; wc -l cron.log logs/daily.log

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
kaito@demo:~/linux-practice/python-test$ date; wc -l cron.log logs/daily.log
Sun Nov  1 05:53:57 JST 2026
  4 cron.log
  6 logs/daily.log
 10 total

Debian 13での実行画面

# をつけた cron.log は 4 行のまま増えず、# をつけていない logs/daily.log は 4 → 6 行に増えました。# をつけた行だけが止まっています。また使うときは、# を消して保存すれば戻ります。

毎分のテストを、毎朝7時に戻す

うまく動くのを確かめたので、daily_job.py の行を本番の時刻に直し、確かめ用の2行(env.log と相対パスの行)は消します。crontab -e で開いて、daily_job.py の行を次のように書きかえ、確かめ用の2行は Ctrl+K(1行切り取り)で消して保存します。

  • 1
0 7 * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/daily_job.py >> /home/kaito/linux-practice/python-test/logs/daily.log 2>&1

  • 1
crontab -e

(例)

  • 1
  • 2
kaito@demo:~/linux-practice/python-test$ crontab -e
crontab: installing new crontab

Debian 13での実行画面

  • 1
  • 2
crontab -l | grep -v "^# "
date; wc -l cron.log logs/daily.log logs/env.log logs/a_relative.log

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
kaito@demo:~/linux-practice/python-test$ crontab -l | grep -v "^# "
#* * * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/hello.py >> /home/kaito/linux-practice/python-test/cron.log 2>&1
0 7 * * * /home/kaito/linux-practice/python-test/venv/bin/python /home/kaito/linux-practice/python-test/daily_job.py >> /home/kaito/linux-practice/python-test/logs/daily.log 2>&1
kaito@demo:~/linux-practice/python-test$ date; wc -l cron.log logs/daily.log logs/env.log logs/a_relative.log
Sun Nov  1 05:54:13 JST 2026
  4 cron.log
  8 logs/daily.log
  2 logs/env.log
  4 logs/a_relative.log
 18 total

1分ほど待ってから、もう一度数えます。

  • 1
date; wc -l cron.log logs/daily.log logs/env.log logs/a_relative.log

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
kaito@demo:~/linux-practice/python-test$ date; wc -l cron.log logs/daily.log logs/env.log logs/a_relative.log
Sun Nov  1 05:55:25 JST 2026
  4 cron.log
  8 logs/daily.log
  2 logs/env.log
  4 logs/a_relative.log
 18 total

Debian 13での実行画面

logs/daily.log は 8 行のまま増えなくなりました。毎分ではなく、次の朝7:00に動くようになったからです。消した2行の env.log と a_relative.log も増えていません。

いらなくなった行を全部消す

練習が終わって、ジョブを全部やめたいときも、crontab -e で開いて行を消します。Ctrl+W で hello.py >> を探し、Ctrl+K を2回押して、残っていた2行を消して保存します。

  • 1
crontab -e

(例)

  • 1
  • 2
kaito@demo:~/linux-practice/python-test$ crontab -e
crontab: installing new crontab

消したあとは、crontab -l で確かめます。

  • 1
  • 2
  • 3
crontab -l
crontab -l | grep -v "^#"
echo $?

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
kaito@demo:~/linux-practice/python-test$ crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
…(途中省略)…
# m h  dom mon dow   command
kaito@demo:~/linux-practice/python-test$ crontab -l | grep -v "^#"
kaito@demo:~/linux-practice/python-test$ echo $?
1

Debian 13での実行画面

crontab -l には Debian の説明文だけが残り、grep -v "^#"(# で始まらない行だけを表示)では何も出ませんでした。echo $? の 1 は、grep が「当てはまる行が1つもなかった」という意味です。これで、動くジョブはなくなりました。

🤖 詰まったらAIに聞こう:cron で Python が動かない

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
Linuxの初心者です。cronで Python のスクリプトを毎朝動かしたいのですが、動きません。
原因の候補と、確かめる順番を教えてください。

【使っている環境】WSLのUbuntu、Debian など
【crontab -l の結果(パスのユーザー名は置き換え済み)】ここに貼る
【ログファイルの最後の20行】ここに貼る
【手で動かしたときの結果】ここに貼る

🔒
AIに貼る前に:秘密情報やパスワードは貼らない

crontab の行やログ、スクリプトには、APIキー、トークン、パスワードがまざっていることがあります。APIキーやトークンは、Web のサービスを使うときに本人の代わりになる、合言葉のような文字列です。AI に貼る前に、それらを必ず「***」に置き換えてください。パスに入っている自分のユーザー名も、example のような言葉に置き換えておくと安心です。sudo で打ったパスワードは、画面にもログにも出ませんが、聞かれても貼らないでください。


動かないときに確認すること

動かないときは、次の順で確認してみましょう。

症状・状況 原因として多いもの 対処
ログに /bin/sh: 1: venv/bin/python: not found 相対パスで書いた。cron の作業フォルダはホーム(/home/kaito) 絶対パスで書く。または cd してから動かす
コマンドが見つからない cron の PATH は /usr/bin:/bin だけ Pythonもスクリプトもフルパスで書く
ModuleNotFoundError venvではなく、システムの python3 で動いている venv/bin/python をフルパスで書く
ログファイルにエラーが残らない 2>&1 がない >> ログ 2>&1 にする
cron自体が動いたのかわからない ジョブが起動していない、または起動したが失敗している sudo journalctl -u cron で CMD の行を探す
journalctl -u cron が -- No entries -- sudo をつけていない sudo journalctl -u cron で見る


失敗に気づく簡単な方法

cronは画面に何も出ないので、失敗しても気づきにくいものです。だから、「失敗したときに気づける形」にしておくのが大切です。難しい仕組みを入れなくても、次の3つだけで十分です。

1. エラーもログに残す(2>&1)

先ほどのとおり、2>&1 があれば、エラーの内容もログに残ります。あとから tail や grep で読み返せます。

  • 1
tail -n 20 /home/kaito/linux-practice/python-test/logs/daily.log

2. スクリプトの最初と最後に、時刻つきの行を出す

この記事の daily_job.py のように「start」と「done」の行があれば、ログを見るだけで、「動いたか」「最後まで終わったか」がわかります。「done」が抜けている日は、途中で失敗している日です。

3. 失敗したら、エラーを出して異常終了させる

daily_job.py は、エラーのときに ERROR の行を標準エラー出力に出して、終了コード 1 で終わるように書いてあります。2>&1 と組み合わせれば、ログに ERROR が残るので、grep ERROR で探せます(この記事では、わざとエラーを起こす操作は試していません)。


注意点

crontab の中の % と MAILTO・@reboot(今回は試していません)

次の項目は、動かして確認していません。cronのマニュアル(crontab(5))に書かれている内容や、一般的な使い方の紹介です。

  • % のエスケープ:crontabのコマンドの中の % は、バックスラッシュ(\)でエスケープしないと、改行として扱われるとマニュアルに書かれています。たとえば date +%F は、date +\%F のように書きます。シェルスクリプトの記事の $(date +%Y%m%d-%H%M%S) のような日付つきの処理は、スクリプトの中に書いておけば、crontabにはスクリプトの名前を書くだけなので、このエスケープを気にせずにすみます。
  • MAILTO:出力を送るメールの宛先を、crontabの MAILTO で指定できる(空にするとメールを送らない)とマニュアルに書かれています。
  • @reboot:「起動時に1回実行する」という書き方があります。

WSLでは、cronが動き続けるとは限らない

WindowsのWSL上でcronを使う場合は、注意が必要です。Microsoftの公式ドキュメントでは、WSLでsystemd(=Linux の起動や、サービスの起動・停止・自動起動を管理するしくみ)を有効にしても、systemdのサービスはWSLのインスタンスを動かし続けないと説明されています(Use systemd to manage Linux services with WSL)。

つまり、WSLにcronを入れても、状況によってはLinux側が止まってしまい、その間はジョブが動かない可能性があります。動き方は、WSLのバージョンや設定など環境により異なります。この記事では、WSLでの動作は確認していません。また、そもそもPCの電源が切れていたりスリープしていたりすれば、当然ジョブは動きません。

毎日確実に動かしたいなら、動かし続けられる場所へ

「毎朝かならず動いてほしい」なら、電源が入ったまま動き続けるLinux環境に置くのが基本です。自分のPCではなく、VPSのような「借りて使うサーバー」に置く、という選択肢があります。ただし、サーバーの管理(更新や設定)は自分で行うことになるので、まずは手元で、この記事のダミーのスクリプトで流れを試してから考えるのがおすすめです。


よくある質問

Q. crontab -e と打ったら「command not found」と出ました。

cronが入っていない環境です。DebianやUbuntuでは、sudo apt install cron で入れられます(Lv2 の apt の記事を参考にしてください)。WSLやコンテナ(=アプリと、動かすのに必要なものをひとまとめにした箱)など、最初からは入っていない環境もあります。入れたあと、cronが動いているかは、この記事の最初と同じ systemctl status cron で確かめます。

Q. WSLで、cronが動いていないようです。

WSLでsystemdを使っていない設定の場合、cronは自動では起動しません。sudo service cron start で起動する方法がありますが、WSLを閉じると止まることがあります(上の「WSLでは、cronが動き続けるとは限らない」を参照)。毎日確実に動かしたいなら、動かし続けられる環境を検討しましょう(WSLでの動きは、この記事では試していません)。

Q. 毎分のテストのジョブは、どうやって止めればいいですか?

crontab -e で開いて、テストの行を消して保存します。あとでまた使うなら、行の先頭に # をつけておくと、残したまま止められます。止めたあとは、crontab -l で確かめましょう。止めないと、ログファイルが毎分増え続けます。

Q. エディタの選択で、まちがえて vim を選んでしまいました。

select-editor と打つと、もう一度選び直せます(はじめての crontab -e の画面に出ていた案内です)。vim の画面から出るときは、Esc を押してから :q! と打って Enter です(保存せずに出ます)。


まとめ

  • cronは、LinuxでのGASの時間主導型トリガーのようなもの。crontab -e で「時刻の5項目 + コマンド」を1行書き、crontab -l で確かめる
  • cron で動くときの作業フォルダはホーム、PATH は /usr/bin:/bin だけ。だから、パスは絶対パス。venvを使うなら、venv/bin/python もフルパスで書く
  • 出力は >> ログ 2>&1 で残す。cron自体の記録は sudo journalctl -u cron で見る
  • 止めるときは crontab -e で、行の先頭に # をつけるか、行を消す。crontab -r は打たない

まずは今日、hello.py のようなスクリプトを毎分で動かして、ログが増えるところを見てみましょう。それができたら、本番の時刻に書き換えるだけです。

Pythonの準備からやり直したい方は、Python入門|環境構築と最初の1本を動かすから、一緒にやってみましょう。スクリプトの書き方(自動化の小さな例)は、Pythonで毎日の作業を自動化する入門|ダウンロードフォルダを自動で整理しようも参考になります。


次に読む記事


関連する本・記事

自動化するスクリプトが増えて、毎朝の処理の重さが気になってきたときの次の一歩として、計測してからPythonを速くする考え方を扱う『爆速Pythonの作り方』もあります。