at による単発予約
「繰り返しではなく、一度だけ後で実行したい」処理には at を使います。at に時刻を渡すと専用のプロンプトが開き、入力したコマンドがその時刻に1回だけ実行されます。予約済みの一覧は atq、取り消しは atrm で扱います。深夜のメンテナンス1回や、数時間後の通知など、cron ほど大げさにしたくない単発タスクに向きます。systemd 環境では systemd-run --on-active でも同様の一時的な予約ができます。
定期的に繰り返すのではなく、「今回だけ、後で1回実行したい」という場面もよくあります。たとえば「30分後にサービスを再起動したい」「今夜2時に1回だけメンテナンス用スクリプトを流したい」「3時間後に通知を出したい」といったケースです。こうした単発の予約には 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 のように日付を添えることもできます。プロンプトに打ち込む代わりに、echo "systemctl restart httpd" | at now + 30 minutes のようにパイプでコマンドを流し込む書き方や、at -f script.sh now + 1 hour のようにファイルを指定する書き方もよく使われ、スクリプトの中から予約を仕込むときに便利です。
予約の確認と取り消し
登録した予約は atq で一覧できます(at -l でも同じです)。各予約には番号(ジョブ番号)が振られ、実行予定時刻・キュー・登録したユーザとともに表示されるので、「ちゃんと入っているか」「いつ動く予定か」を確認できます。予約を取り消したいときは atrm 番号(at -d 番号 でも可)で、atq に出た番号を指定して削除します。複数の予約を入れたが一部だけ消したい、というときも番号で個別に取り消せるので、間違えて入れてしまった予約を安全に撤回できます。予約の中身、つまり実際に何が実行されるのかを確かめたいときは at -c 番号 とすると、そのジョブが実行される際に使われる環境変数も含めた全文が表示されます。ここで表示される環境は、登録した時点の環境変数を at が記録して再現したものなので、「登録したけれど本当に意図どおりか不安」というときに、この -c で中身と環境を点検しておくと安心です。実行結果は cron と同じく、標準出力・標準エラーへの出力がそのユーザ宛にメールされようとするため、確実に結果を残したいなら、予約するコマンドの側で >> /var/log/at-job.log 2>&1 のようにログファイルへリダイレクトしておくのが堅実です。なお、似た用途で batch というコマンドもあり、こちらは時刻を指定せず「システムの負荷が下がったタイミングで実行する」ため、急がない重い処理を空いた時間に回したいときに使えます。
atd と環境、よくある失敗
at の予約を実際に動かすのは atd というデーモンです。ここで初学者がとてもはまりやすいのが、atd が動いていないと、予約はできても時間が来ても何も実行されない、という点です。「at で登録したのに動かない」ときは、まず systemctl status atd でデーモンが稼働しているかを確認し、止まっていれば systemctl enable --now atd で起動・有効化します。これは cron で crond の稼働を確認するのと同じ勘どころです。また、at で実行されるコマンドも cron と同様にログインシェルを通さないため、環境変数や PATH が普段の対話シェルとは異なる点に注意が必要です。手で打つと動くのに at だと失敗する、という症状の典型的な原因がこれで、対策はコマンドを絶対パスで書く、必要な環境変数をスクリプト内で明示する、といった cron の場合とまったく同じ考え方になります。なお、誰が at を使えるかは /etc/at.allow と /etc/at.deny で制御されており、環境によっては一般ユーザの利用が制限されていることもあります。
systemd-run という代替
systemd が標準の環境では、一時的な単発予約を at の代わりに systemd-run で行うこともできます。たとえば systemd-run --on-active=30min systemctl restart httpd とすると、「今から30分後に httpd を再起動する」一時的なタイマーがその場で作られ、1回実行されたら自動的に片付けられます。--on-calendar="02:00" のように時刻で指定することも可能です。at と違って実行ログが journal に残るため、後から結果を追いやすいのが利点で、--unit=mytask のように名前を付けておけば journalctl -u mytask でそのジョブのログだけを確認できます。手軽さやどの環境でも使える可搬性では at、ログ統合や systemd との一貫性を重視するなら systemd-run、というように、その場限りの単発タスクにも2つの選択肢があると覚えておくとよいでしょう。いずれにせよ「繰り返しは cron や systemd timer、一度きりは at や systemd-run」という対応を押さえておけば、用途に応じて最短の道具を迷わず選べます。