CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Scheduling / at

at

Run a command once at a later time

Beginnerschedulingone-off

at queues a command to run once at a given time ('23:00', 'now + 30 minutes', '9am next monday'). The atd daemon runs it later, even after you log out. atq lists pending jobs, at -c shows what a job will run, and atrm cancels one.

Syntaxat [-f FILE] [-q QUEUE] [-m] TIME | atq | at -c JOB | atrm JOB...

Watch it run

Rotate an API key tonight at 23:00, outside business hours, without staying logged in.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 4
echo '/home/devops/bin/rotate-keys.sh' | at 23:00

at confirms the job number and the exact run time. The warning is normal: the job runs under sh, not your bash.

Anatomy of a command

$
commandecho '/opt/scripts/rotate-keys.sh'

at reads the job's commands from stdin (or from -f FILE). Without a pipe it opens an at> prompt; end it with Ctrl+D.

How it works

at parses the time spec, then writes an executable shell script to /var/spool/cron/atjobs. The filename encodes the queue letter, the job number and the run time in minutes since the epoch. The script first recreates your current environment: every exported variable, your umask and a cd to the directory you were in. Then come your commands. at then signals atd (via its PID file in /run) to look again. atd sleeps until the next due job, checks /etc/at.allow and at.deny, runs the script with /bin/sh as your user, captures its output and mails it to you through the local MTA. Jobs are stored on disk, so they survive reboots and run when atd starts again. If atd isn't running, at still queues the job but warns that it can't signal the daemon. Queue 'a' is the default; batch uses 'b', and running jobs show as '='.

Options you'll actually use

TIMEHH:MM, noon, midnight, now + N minutes|hours|days, 9am next monday, 10:30 2026-11-02
-f FILERead the job's commands from FILE instead of stdin
-mMail when done, even without output
-q LETTERUse queue LETTER (a default, b = batch, later letters = nicer)
-l / atqList your pending jobs (root sees everyone's)
-c JOBPrint the full script a job will run
-r JOB / atrm JOBDelete a pending job
-t [[CC]YY]MMDDhhmmExact time in touch-style format

Common mistakes

at 23:00 ./cleanup.sh

at doesn't take the command as an argument. It reads commands from stdin, so './cleanup.sh' is parsed as part of the time and fails.

echo '/home/kunal/cleanup.sh' | at 23:00 # or: at -f cleanup.sh 23:00
Using bash syntax ([[ ]], arrays, source) in an at job

Jobs run under /bin/sh (dash on Ubuntu).

echo 'bash /home/kunal/job.sh' | at now + 1 hour
Assuming the job ran because at accepted it

If atd isn't running, jobs just sit in the queue. Output is mailed, and without an MTA you see nothing.

systemctl is-active atd; redirect output: cmd >> /tmp/job.log 2>&1
Using at for something that must happen every night

at runs once. Re-queueing from inside the job is fragile.

crontab -e or a systemd timer

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Schedule a job that writes 'hello from at' to /tmp/at-test.txt in 2 minutes. Check that it's queued.

  2. 2

    Show the full script that job will run and find the line that changes directory.

  3. 3

    Queue a job for tomorrow at noon, then cancel it.

  4. 4

    Wait for the first job to run and confirm its output.

Related commands

batchRun a job when the system is idle enoughcrontabSchedule recurring jobs with cronsleepPause for a set time (retries, polling, containers)
PreviouscrontabNextbatch
Linux / Scheduling / at

at

Run a command once at a later time

Beginnerschedulingone-off

at queues a command to run once at a given time ('23:00', 'now + 30 minutes', '9am next monday'). The atd daemon runs it later, even after you log out. atq lists pending jobs, at -c shows what a job will run, and atrm cancels one.

Syntaxat [-f FILE] [-q QUEUE] [-m] TIME | atq | at -c JOB | atrm JOB...

Watch it run

Rotate an API key tonight at 23:00, outside business hours, without staying logged in.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 4
echo '/home/devops/bin/rotate-keys.sh' | at 23:00

at confirms the job number and the exact run time. The warning is normal: the job runs under sh, not your bash.

Anatomy of a command

$
commandecho '/opt/scripts/rotate-keys.sh'

at reads the job's commands from stdin (or from -f FILE). Without a pipe it opens an at> prompt; end it with Ctrl+D.

How it works

at parses the time spec, then writes an executable shell script to /var/spool/cron/atjobs. The filename encodes the queue letter, the job number and the run time in minutes since the epoch. The script first recreates your current environment: every exported variable, your umask and a cd to the directory you were in. Then come your commands. at then signals atd (via its PID file in /run) to look again. atd sleeps until the next due job, checks /etc/at.allow and at.deny, runs the script with /bin/sh as your user, captures its output and mails it to you through the local MTA. Jobs are stored on disk, so they survive reboots and run when atd starts again. If atd isn't running, at still queues the job but warns that it can't signal the daemon. Queue 'a' is the default; batch uses 'b', and running jobs show as '='.

Options you'll actually use

TIMEHH:MM, noon, midnight, now + N minutes|hours|days, 9am next monday, 10:30 2026-11-02
-f FILERead the job's commands from FILE instead of stdin
-mMail when done, even without output
-q LETTERUse queue LETTER (a default, b = batch, later letters = nicer)
-l / atqList your pending jobs (root sees everyone's)
-c JOBPrint the full script a job will run
-r JOB / atrm JOBDelete a pending job
-t [[CC]YY]MMDDhhmmExact time in touch-style format

Common mistakes

at 23:00 ./cleanup.sh

at doesn't take the command as an argument. It reads commands from stdin, so './cleanup.sh' is parsed as part of the time and fails.

echo '/home/kunal/cleanup.sh' | at 23:00 # or: at -f cleanup.sh 23:00
Using bash syntax ([[ ]], arrays, source) in an at job

Jobs run under /bin/sh (dash on Ubuntu).

echo 'bash /home/kunal/job.sh' | at now + 1 hour
Assuming the job ran because at accepted it

If atd isn't running, jobs just sit in the queue. Output is mailed, and without an MTA you see nothing.

systemctl is-active atd; redirect output: cmd >> /tmp/job.log 2>&1
Using at for something that must happen every night

at runs once. Re-queueing from inside the job is fragile.

crontab -e or a systemd timer

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Schedule a job that writes 'hello from at' to /tmp/at-test.txt in 2 minutes. Check that it's queued.

  2. 2

    Show the full script that job will run and find the line that changes directory.

  3. 3

    Queue a job for tomorrow at noon, then cancel it.

  4. 4

    Wait for the first job to run and confirm its output.

Related commands

batchRun a job when the system is idle enoughcrontabSchedule recurring jobs with cronsleepPause for a set time (retries, polling, containers)
PreviouscrontabNextbatch