at command


at - execute commands at a later time

It’s like a one-off cron job.

I’ve had a task to perform verification of a new import script against the current implementation. Verification involves comparing the result of data changes between two days. However, I’ve failed to capture a snapshot of the data two days in a row more than once now. So, this time, when I triggered a snapshot of the data, I've set an at-job to run the same job again tomorrow so that I get that snapshot to verify later.

Notes on MacOS

⚠️ A note about MacOS: This functionality is disabled by default and needs to be enabled before it will work. See the Making “at” work on MacOS discussion on StackExchange.

  1. Give /usr/libexec/atrun Full Disk Access in Security & Privacy preferences.
  2. Enable the atrun utility with launchd.

Creating an “at-job”

There are a couple of ways to create the job.

Pass the command directly in through standard input:

$ echo 'make pg-pull' | at 9am tomorrow

Or; set the command interactively:

$ at 9am tomorrow
make pg-pull

When creating a job interactively, you:

  1. type in the at … command, press ENTER
  2. type in the command(s) to run later, press ENTER for each line
  3. then press Control-D to end the input

Now, my make pg-pull command will run tomorrow at 9am. Pretty obvious. Also nice that the time and date specifiers are relatively friendly.

Where’s the proof?

List the jobs I've created:

$ at -l
3	Tue Dec  8 09:00:00 2020

See what’s in the job:

$ at -c 3
# atrun uid=502 gid=20
# mail travis 0
PWD=/Users/travis/work/tps/tpsdata; export PWD
OLDPWD=/Users/travis/work/tps/tpsdata; export OLDPWD
_=/usr/bin/at; export _
cd /Users/travis/work/tps/tpsdata || {
	 echo 'Execution directory inaccessible' >&2
	 exit 1
OLDPWD=/Users/travis/work/tps/tpsdata; export OLDPWD
make pg-pull

💡 A cool point is that the job will be generated with your current environment, including your current directory. So tomorrow when it runs, it will change back to the directory I’m currently in and run the command from there.

Now what?

Now we wait.


Control-C vs Control-D

When starting to use the terminal, it’s inevitable that you come across running a command that remains running and the direction is to press Control-C to stop it.

And sometimes, you may be directed to press Control-D.

But what’s the difference? Why did one work one time and not the other?

continue →