atrm Command in Linux: Complete Guide to Removing Scheduled Jobs and Parameters

atrm command in Linux and it perimeters

Scheduling a one-time job with at is easy. Un-scheduling one you made a mistake on — or one that’s no longer needed because the situation changed — is what atrm is for. It’s a tiny command, but it’s saved me more than once from a job firing off at 3 AM that I really didn’t want running anymore.

What atrm Actually Is

atrm removes one or more pending jobs from the at job queue, identified by the job number that at assigned when the job was scheduled (and that atq shows you). It’s part of the same at package as at, atq, and the background atd daemon. Functionally, atrm is equivalent to at -d, which does the identical operation under a different flag on the base at command.

Basic Syntax

atrm job_id [job_id ...]

You need at least one job ID. There’s no interactive mode and no confirmation prompt — atrm deletes silently and immediately, so it’s worth double-checking the job ID before you run it.

A Basic Example

First, find the job number with atq:

atq
3    Fri Jul 31 22:00:00 2026 a john
4    Sat Aug  1 09:00:00 2026 a john

Then remove it:

atrm 3

No output on success. Verify it’s gone:

atq
4    Sat Aug  1 09:00:00 2026 a john

Job 3 is no longer listed and will not execute.

Removing Multiple Jobs at Once

atrm 3 4 7

Each job ID is processed independently — if one ID doesn’t exist or belongs to another user (and you’re not root), atrm reports an error for that specific ID but still processes the rest of the list.

atrm 99
atrm: 99: No such file or directory

Options

atrm itself has essentially no options beyond the job ID list — it’s intentionally a one-trick command. The equivalent functionality via the base at command does support a couple of related flags:

at -d job_id     # identical to atrm job_id

There’s no -f (force) or -i (interactive confirm) flag on standard atrm — deletion is immediate and unconditional, which is worth remembering, especially in scripts.

Permissions and Ownership

A regular user can only remove their own jobs. If you try to remove another user’s job without root privileges:

atrm 5
atrm: 5: Permission denied

Root can remove any job on the system, from any user:

sudo atrm 5

Real-World Examples

Clearing every job you personally have pending:

atq | awk '{print $1}' | xargs -r atrm

The -r flag on xargs prevents it from running atrm with no arguments at all if atq returns nothing, which would otherwise produce an unhelpful “at least one job ID required” error.

Removing a job by matching its command content:

Since atrm only works with job numbers, and atq doesn’t show the actual command, you typically need to combine it with at -c to find the right job first:

for job in $(atq | awk '{print $1}'); do
    if at -c "$job" | grep -q "old_backup_script.sh"; then
        echo "Removing job $job (matches old_backup_script.sh)"
        atrm "$job"
    fi
done

Cancelling a scheduled maintenance action if a deployment is aborted:

#!/bin/bash
# deploy.sh
JOB_ID=$(echo "systemctl restart myapp" | at now + 20 minutes | grep -oP 'job \K[0-9]+')
echo "Scheduled restart as job $JOB_ID"

# ... later, if deployment fails and restart should be cancelled:
if [ "$DEPLOY_FAILED" = true ]; then
    atrm "$JOB_ID"
    echo "Cancelled scheduled restart (job $JOB_ID)"
fi

This pattern — capturing the job ID at scheduling time so it can be cancelled conditionally later — is one of the more valuable uses of atrm in automation, since it lets a script “undo” a previously scheduled action based on later events.

Cleaning up stale jobs older than a certain queue letter or pattern (admin housekeeping, as root):

sudo atq | awk '$5=="olduser" {print $1}' | xargs -r sudo atrm

Removes all pending jobs belonging to a user named olduser, for example as part of an account decommissioning process.

What Happens Under the Hood

Each pending at job is stored as an individual file in the spool directory (commonly /var/spool/cron/atjobs/), with a filename that encodes the job number, queue letter, and scheduled time. atrm simply locates and deletes the corresponding spool file (with appropriate permission checks first). Because the atd daemon works directly off this spool directory, removing the file is immediately effective — there’s no separate “queue database” to update or daemon to notify or restart.

Troubleshooting

“atrm: job_id: No such file or directory” — the job either already ran, was already removed, or the ID was mistyped. Double-check with atq first.

“atrm: job_id: Permission denied” — you’re trying to remove a job that belongs to a different user; you’ll need root (sudo atrm job_id).

Job still shows in atq after running atrm — very rare, but can happen if there’s a permissions issue on the spool directory itself preventing deletion; check ownership and permissions on /var/spool/cron/atjobs/ and check atd‘s logs.

“atrm: command not found” — the at package isn’t installed; install with apt install at or dnf install at — this also installs at, atq, and atd.

Accidentally removed the wrong job — there’s no undo. This is exactly why I always run atq and, for anything important, at -c job_id to confirm the contents, immediately before running atrm.

Security Considerations

Comparison to Related Commands

atrm‘s behavior is consistent across Debian, Ubuntu, RHEL, CentOS, Fedora, and SUSE — it’s the same upstream at package everywhere, so scripts using it are highly portable.

Summary

atrm is a small, blunt, and completely reliable tool: give it a job ID, and that job is gone from the queue, immediately and without ceremony. The only real skill involved is knowing which job ID you actually want to remove — which is why atq (and at -c for double-checking contents) should always be your first stop before reaching for atrm.

References

Exit mobile version