🐧 Linux 総合学習プラットフォーム
自動化/定期実行 ・ 中級

at による単発予約

「繰り返しではなく、一度だけ後で実行したい」処理には at を使います。at に時刻を渡すと専用のプロンプトが開き、入力したコマンドがその時刻に1回だけ実行されます。予約済みの一覧は atq、取り消しは atrm で扱います。深夜のメンテナンス1回や、数時間後の通知など、cron ほど大げさにしたくない単発タスクに向きます。systemd 環境では systemd-run --on-active でも同様の一時的な予約ができます。

繰り返しではなく、今回だけ後で1回動かしたい。そういう場面に使うのが at だ。

「30分後にサービスを再起動したい」「今夜2時に1回だけメンテナンス用スクリプトを流したい」「3時間後に通知を出したい」――こうした単発の予約に、cron を持ち出すのは大げさだ。

💡
ポイントat は「一度きり」の予約に使う道具。cron が「毎回」のための道具なのに対し、用途がはっきり分かれている。

cron が「毎回」のための道具なのに対し、at は「一度きり」のための道具で、用途がはっきり分かれている。

cron(毎回)同じ予定が繰り返し動くat(一度きり)実行が済めば予約は自動で消える

一度きりの処理をわざわざ crontab に書いてしまうと、実行が済んだ後に行を消し忘れて意図せず動き続ける、という事故になりがちだ。at を使えばそうした後始末が要らない。実行が終われば予約は自動的に消えるので、単発タスクにはこちらが向く。

🗣 時刻の指定は、どこまで自然に書けるのか

at の使い方はシンプルだ。実行したい時刻を引数として渡すと、コマンドを入力する専用のプロンプト(at> )が開く。

そこに実行したいコマンドを1行ずつ打ち込み、最後に Ctrl + d を押して入力を終える。すると、その時刻に1回だけ実行する予約が登録される。

時刻の指定が自然言語に近く柔軟なのが特徴だ。at 02:00 と打てば今夜(既に過ぎていれば翌日)の午前2時。at now + 30 minutes なら今から30分後。at now + 3 hours なら3時間後。at 17:00 tomorrow なら明日の17時。at midnight なら今夜の0時。at 10:00 AM Jul 31 のように日付を添えることもできる。

at now + 30 minutes ……今から30分後。at 02:00 なら今夜(過ぎていれば翌日)の午前2時。時刻指定が自然言語に近い。
コツat 17:00 tomorrow・at midnight・at 10:00 AM Jul 31 のように、明日・今夜0時・日付指定も書ける。融通が利く。

プロンプトに打ち込む以外の書き方もよく使われる。echo \"systemctl restart httpd\" | at now + 30 minutes のようにパイプでコマンドを流し込む書き方や、at -f script.sh now + 1 hour のようにファイルを指定する書き方だ。スクリプトの中から予約を仕込むときに便利になる。

echo \"systemctl restart httpd\" | at now + 30 minutes ……パイプで流し込む書き方。at -f script.sh now + 1 hour ならファイル指定。

📋 入れた予約は、どう確認して取り消すのか

登録した予約は atq で一覧できる(at -l でも同じだ)。

各予約には番号(ジョブ番号)が振られる。実行予定時刻・キュー・登録したユーザとともに表示されるので、「ちゃんと入っているか」「いつ動く予定か」を確認できる。

atq(at -l でも可)で予約を一覧、atrm 番号(at -d 番号 でも可)で取り消す。番号は atq に出たものを指定する。

予約を取り消したいときは atrm 番号(at -d 番号 でも可)を使う。atq に出た番号を指定して削除する。

複数の予約を入れたが一部だけ消したい、というときも番号で個別に取り消せる。間違えて入れてしまった予約を安全に撤回できる。

予約の中身、つまり実際に何が実行されるのかを確かめたいときは at -c 番号 とする。すると、そのジョブが実行される際に使われる環境変数も含めた全文が表示される。

コツat -c 番号 で予約の中身を全文表示できる。実行時の環境変数も含むので「本当に意図どおりか」を登録後に点検できる。

ここで表示される環境は、登録した時点の環境変数を at が記録して再現したものだ。「登録したけれど本当に意図どおりか不安」というときに、この -c で中身と環境を点検しておくと安心だ。

実行結果は cron と同じだ。標準出力・標準エラーへの出力がそのユーザ宛にメールされようとする。確実に結果を残したいなら、予約するコマンドの側で >> /var/log/at-job.log 2>&1 のようにログファイルへリダイレクトしておくのが堅実である。

なお、似た用途で batch というコマンドもある。こちらは時刻を指定せず「システムの負荷が下がったタイミングで実行する」ため、急がない重い処理を空いた時間に回したいときに使える。

⚠ 「予約したのに動かない」のは、なぜか

ここで初学者がとてもはまりやすい落とし穴を外しておきたい。at の予約を実際に動かすのは atd というデーモンだ。atd が動いていないと、予約はできても時間が来ても何も実行されない。

つまずきat の予約を動かすのは atd デーモン。atd が止まっていると、予約はできても時間が来ても何も実行されない。

「at で登録したのに動かない」ときは、まず systemctl status atd でデーモンが稼働しているかを確認する。止まっていれば systemctl enable --now atd で起動・有効化する。これは cron で crond の稼働を確認するのと同じ勘どころだ。

systemctl status atd で稼働確認。止まっていれば systemctl enable --now atd で起動・有効化する。

また、at で実行されるコマンドも cron と同様にログインシェルを通さない。そのため、環境変数や PATH が普段の対話シェルとは異なる点に注意が必要になる。

手で打つと動くのに at だと失敗する、という症状の典型的な原因がこれだ。対策はコマンドを絶対パスで書く、必要な環境変数をスクリプト内で明示する、といった cron の場合とまったく同じ考え方になる。

なお、誰が at を使えるかは /etc/at.allow と /etc/at.deny で制御されている。環境によっては一般ユーザの利用が制限されていることもある。

🔧 systemd が標準なら、at の代わりはあるのか

systemd が標準の環境では、一時的な単発予約を at の代わりに systemd-run で行うこともできる。

たとえば systemd-run --on-active=30min systemctl restart httpd とすると、「今から30分後に httpd を再起動する」一時的なタイマーがその場で作られ、1回実行されたら自動的に片付けられる。--on-calendar=\"02:00\" のように時刻で指定することも可能だ。

systemd-run --on-active=30min systemctl restart httpd ……30分後に1回 httpd を再起動する一時タイマーをその場で作る。

at と違って実行ログが journal に残るため、後から結果を追いやすいのが利点だ。--unit=mytask のように名前を付けておけば journalctl -u mytask でそのジョブのログだけを確認できる。

コツsystemd-run に --unit=mytask と名前を付けると、journalctl -u mytask でそのジョブのログだけを後から追える。

手軽さやどの環境でも使える可搬性では at、ログ統合や systemd との一貫性を重視するなら systemd-run、というように、その場限りの単発タスクにも2つの選択肢があると覚えておくとよい。

いずれにせよ「繰り返しは cron や systemd timer、一度きりは at や systemd-run」という対応を押さえておけば、用途に応じて最短の道具を迷わず選べる。

この項目に出てくる用語

cronクロン
決まった時刻や間隔でコマンドを自動実行する、Unix系OS標準のスケジューラ。

関連コマンド

atatqsystemd-run

▶ 学習アプリでこの続きを学ぶ・演習する