atコマンドで指定時間にJobを単発実行させる

はじめに

最近、CrontabみたいなJobを定期的にスケジュールするのでは無くて、指定時間に単発で実行したいみたいな要件にぶち当たって、ちょっと調べていたらUnix系のOSにatというコマンドがあることに気がついたので機能を試して見ようかと思います。

at コマンドとは

標準出力、もしくはファイルからコマンドを受け取って、/bin/shを使って指定時間にシェルを起動するコマンドです。Corntabなどは日時の指定のみで、最長一年に一回は実行されるのに対してatコマンドは年の指定まで行なうことが可能で、指定した時間に一回のみといった実行が行えます。
実行時の環境変数BASH_VERSINFODISPLAYEUID, GROUPSSHELLOPTSTERMUID以外)、ワークディレクトリ、umaskなどはコマンド実行時の状態でキープされます。
また、atsetuidプログラムで、LD_LIBRARY_PATHLD_PRELOADなどの環境変数も読み込まれないようです。

使ってみる

環境

コマンドの実行環境は以下の通り、

$ uname -srvmpio
Linux 5.4.0-62-generic #70-Ubuntu SMP Tue Jan 12 12:45:47 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
LSB Version:    core-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.1 LTS
Release:    20.04
Codename:   focal

基本的な操作方法

プロンプトでコマンドを設定する。

atは以下のような形式で、実行できます。

$ at 07:55 01/31/21
warning: commands will be executed using /bin/sh
at> 

実行すると、>atという表示が現れプロンプトが起動します。
ここにコマンドを打ち込んでctrl+dを押すと設定が完了です。

$ at 10:46 01/22/21
warning: commands will be executed using /bin/sh
at> java --version > test.txt
at> <EOT>
job 6 at Fri Jan 22 10:46:00 2021

実施時間をすぎると以下のようにテキストが出力されているのが確認できます。

$ cat test.txt 
openjdk 15.0.1 2020-10-20
OpenJDK Runtime Environment AdoptOpenJDK (build 15.0.1+9)
Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.23.0, JRE 15 Linux amd64-64-Bit Compressed References 20201022_81 (JIT enabled, AOT enabled)
OpenJ9   - 0394ef754
OMR      - 582366ae5
JCL      - ad583de3b5 based on jdk-15.0.1+9)

ファイルを読み込んで実行する

atコマンドはファイルを読み込んで実行することもできます。
まずは、以下のようなシェルスクリプトを用意します。

hello.sh

#!/bin/sh

echo "hello, at command" > test.txt

このシェルスクリプトatコマンドで実行するには-fオプションで実行するファイルを指定します。

$ at 21:05 01/22/21 -f hello.sh 
warning: commands will be executed using /bin/sh
job 8 at Fri Jan 22 21:05:00 2021

$ cat test.txt
hello, at command

日付の指定の形式について

atPOSIX.2 standardを拡張した日付の指定が可能なようです。

  • HH:MM
    • 時間と分を指定できます。この場合、今日の時間にJobが実行され、もしその時間が今日すでに過去である場合は次の日の指定された時間にJobが実行されます。
  • MMDD[CC]YY, MM/DD/[CC]YY, DD.MM.[CC]YY or [CC]YY-MM-DD
    • オプションとして、上記のような形式で年月日を指定することができます。
  • midnightnoonteatime
    • それぞれの時間に実行されます。
  • todaytomorrow
    • サーフィクスとして上記の表記をつけるとそれぞれ今日と明日を示すことができます。

その他にも結構自由な時間の指定ができるようで、今日から3日後の4pmとかを指定する場合はat 4pm + 3 days、6月31日の10時AMを指定したい場合はat 10am Jul 31と行ったような感じで指定することができます。

他にできそうなこと

マニュアルでatコマンドを調べてみると、このコマンドには以下のような、仲間がいるようです。

  • atq

    • ペンディングされているUserのJobの一覧を取得します。superuserであるばあいはすべてのJobを出力します。-lオプションがエイリアスになっています。
  • atrm

    • job numberにとって特定されるジョブを削除します。-rオプションがエイリアスになっています。
  • batch

    • システムのロードアベレージが1.5(かもしくはatdコマンドで指定された値)以下になった際にJobを実行する。

他にも-m使うなどするとジョブの実行時にユーザにメールを送ることができるようです。