at queues a single command to run once, later, without a cron line for something that only ever happens once. This guide queues a job, finds its job number, inspects exactly what was queued, and removes it before it runs. The examples use the Debian at package installed here, version 3.2.5. You need a shell account permitted to use at; most steps take less than five minutes and do not require elevated privileges.
First confirm the executable and ask it for its version. This does not create a job or change system state.
$ command -v at
$ at -V
at version 3.2.5
Record the version when you are diagnosing a time expression or a queueing problem. The command is normally serviced by the atd daemon. If submission fails because the daemon is unavailable, that is an administrator's job to restore, not a reason to bolt on an ad hoc privileged scheduler.
Pass a time expression to at, then give it the command on standard input. This example writes a marker below your home directory. Replace the path with a location you own, and pick a time at least a few minutes ahead so there is time to inspect the job.
$ at 16:00 tomorrow
at> printf '%s\n' 'one-off job ran' > "$HOME/at-check.txt"
at> <EOT>
job 42 at Wed Sep 23 16:00:00 2026
The job number is the part worth remembering; your number and date will differ. The command runs under /bin/sh, not necessarily your interactive shell, so quote paths and stick to syntax sh accepts.
For a script or a longer command, put the job in a file and use -f instead. The file is read at submission time, so later edits to it do not touch the queued copy.
$ cat > /tmp/at-example.sh <<'EOF'
printf '%s\n' 'backup step ran' > "$HOME/backup-marker.txt"
EOF
$ at -f /tmp/at-example.sh 16:00 tomorrow
A temporary job file is convenient for testing, but delete it after submission if it holds anything sensitive: the queued job keeps its own copy of the environment and command text even after the original file is gone.
atq lists your pending jobs before you walk away from the shell: job number, scheduled date, time, queue and username. at -l gives the same list.
$ atq
42 Wed Sep 23 16:00:00 2026 a alice
$ at -l 42
42 Wed Sep 23 16:00:00 2026 a alice
On this installation, the normal at queue is a. A superuser's listing covers every user's pending jobs, so avoid running atq with unnecessary privilege; an ordinary user only sees their own.
Common forms include a clock time such as 16:00, named times such as noon and midnight, and relative expressions such as now + 15 minutes. A date follows the time when you supply both.
$ at 16:00 tomorrow
$ at now + 15 minutes
$ at 10am Jul 31
$ at 01:00 2027-01-02
If a clock time has already passed today, at schedules it for the next day instead. A fully specified time and date already in the past is treated as soon as possible, which can be surprisingly soon. Check the confirmation line, then atq, rather than trusting that the parser read the date the way you meant it. The full grammar lives in /usr/share/doc/at/timespec.
For machine-generated schedules, use -t with the documented format [[CC]YY]MMDDhhmm[.ss]. It removes the ambiguity of the human-readable forms, but the value still has to represent the local time you actually intend.
By default, standard output and standard error are mailed only when there is output. Add -m for completion mail even when the command stays quiet, or -M to suppress mail entirely. Mail delivery goes through /usr/sbin/sendmail, so it needs configuring separately from job scheduling.
$ at -M 16:00 tomorrow
at> /usr/bin/logger --tag at-example 'one-off job ran'
at> <EOT>
DISPLAY, TERM and the identity-related shell variables.Set LD_LIBRARY_PATH or LD_PRELOAD explicitly only when you genuinely need them, and understand the security consequences before you do.
Before letting a job that changes data run, inspect the command stored for its job number. This is a read-only check.
$ at -c 42
Look through the output for an unexpected path, an unquoted expansion, or a destructive command. If the job is wrong, cancel it by number: cancellation is the recovery action for a pending job, but it cannot undo work that has already started.
$ atrm 42
$ atq 42
A successful removal leaves no matching line in that second command's output. at -r 42 and at -d 42 do the same thing. Confirm the job number first: removing the wrong job is easy when several are queued.
batch reads a command the same way as at, but waits until the system load permits execution. In this package, the default threshold is a load average below 1.5, or the value configured when atd was started.
$ batch
at> /usr/local/bin/rebuild-search-index
at> <EOT>
The command still runs later under /bin/sh and should be treated as a real state change, so only queue it when a delayed start is acceptable. Uppercase queues supplied with -q also get batch-style load handling, and higher queue letters run with increased niceness. The default queue for at is a, while batch uses b.
Ordinary scheduling is a user operation. The superuser can use these commands regardless of the access files, but that does not make a job safe: a root-owned job can modify the whole system. Do not reach for sudo at ... just to make a command work unless the job genuinely needs root, and then review every path and expansion first.
For non-root users, permission is controlled by /etc/at.allow and /etc/at.deny. Changing either file needs administrator access and affects who may schedule jobs at all, so treat it as a host-wide policy change, not a troubleshooting shortcut. If you are denied, ask the administrator to check the policy and the daemon.
at -V reports the installed version, currently 3.2.5 here.atq showed the pending job you expected.at -c JOB to inspect any important command.atrm JOB cancels a pending job, but cannot undo a job already running.