Page 1 of 1

Task Automation on Linux — cron, at & Shell Scripting Basics

Posted: Sat Jun 13, 2026 1:26 pm
by Murali Krishna
Task Automation on Linux — cron, at & Shell Scripting Basics
A clear, beginner-friendly guide to scheduling jobs and writing your first scripts, with copy-ready examples (AlmaLinux 9 / RHEL 9)

─────────────────────────────────────────
Why automate?
If you do a task more than twice by hand, the computer should be doing it for you. cron runs jobs on a repeating schedule, at runs a job once at a set time, and shell scripts bundle many commands into one reusable file. Together they turn repetitive admin work into "set it and forget it."
─────────────────────────────────────────

1 cron — repeating, scheduled jobs

cron is a background service (cronie on AlmaLinux 9) that runs commands on a schedule. Each user has their own crontab — a list of "run this command at this time" lines.

Edit and view your crontab

Code: Select all

crontab -e          # edit your scheduled jobs
crontab -l          # list your scheduled jobs
crontab -r          # remove all your jobs (careful!)
The five time fields
Every cron line has five time fields, then the command:

Code: Select all

# ┌─ minute (0-59)
# │ ┌─ hour (0-23)
# │ │ ┌─ day of month (1-31)
# │ │ │ ┌─ month (1-12)
# │ │ │ │ ┌─ day of week (0-6, Sunday=0)
# │ │ │ │ │
#   *   *   *   *   *   command-to-run
Real examples

Code: Select all

0 2 * * *      /usr/local/bin/backup.sh     # every day at 02:00
*/15 * * * *   /usr/local/bin/check.sh      # every 15 minutes
0 9 * * 1      /usr/local/bin/report.sh     # every Monday at 09:00
30 23 1 * *    /usr/local/bin/monthly.sh    # 23:30 on the 1st of each month
Tip: An asterisk (*) means "every." Use the website crontab.guru style logic in your head: read each field left to right as minute, hour, day, month, weekday. Always use full paths to commands inside cron — it runs with a minimal environment.

─────────────────────────────────────────

2 at — run something once, later

Where cron repeats, at schedules a single job for a future time, then forgets it.

Make sure the service is running

Code: Select all

systemctl enable --now atd
Schedule a one-off job

Code: Select all

at 22:00                      # then type commands, end with Ctrl+D
# or pipe a command straight in:
echo "systemctl restart nginx" | at now + 1 hour
Manage queued jobs

Code: Select all

atq                           # list pending jobs
atrm 3                        # remove job number 3
Tip: at understands friendly times like "now + 30 minutes", "midnight", "tomorrow 09:00", and "next friday".

─────────────────────────────────────────

3 Shell Scripting — your first script

A shell script is just a text file of commands the shell runs top to bottom. The first line (the "shebang") tells the system which interpreter to use.

Create, make executable, run

Code: Select all

#!/bin/bash
echo "Hello from my first script"

Code: Select all

chmod +x hello.sh             # make it executable
./hello.sh                    # run it
Tip: Start every bash script with #!/bin/bash on line 1. Add "set -euo pipefail" just below it to make the script stop on errors instead of carrying on silently.

─────────────────────────────────────────

4 Variables — storing values

Variables hold text or numbers you reuse. No spaces around the = sign, and put $ in front to read the value.

Code: Select all

#!/bin/bash
name="Murali"
count=5

echo "Hello $name"            # use ${name} when unsure of boundaries
echo "Count is $count"

# Capture a command's output into a variable:
today=$(date +%F)
echo "Today is $today"
Tip: Always quote your variables ("$name", not $name) so values with spaces don't break the command. This one habit prevents most beginner script bugs.

─────────────────────────────────────────

5 Conditions — making decisions

Conditions let a script choose what to do. The "if" runs a test; the part in [ ] is the test.

Code: Select all

#!/bin/bash
file="/etc/hosts"

if [ -f "$file" ]; then
    echo "$file exists"
else
    echo "$file is missing"
fi
Common test operators
  • -f file exists, -d directory exists, -z string is empty
  • -eq -ne -lt -gt -le -ge for NUMBERS (equal, not-equal, less, greater...)
  • = != for STRINGS

Code: Select all

# Number example:
count=10
if [ "$count" -gt 5 ]; then
    echo "More than five"
fi
Tip: Numbers use -gt/-lt/-eq; strings use >/</=. Mixing them up is the classic scripting mistake. Always leave spaces inside the brackets: [ "$x" -gt 5 ], never [$x-gt5].

─────────────────────────────────────────

6 Loops — repeating work

Loops run the same block many times — over a list, or while a condition holds.

for loop — go through a list

Code: Select all

#!/bin/bash
for service in sshd nginx firewalld; do
    echo "Checking $service..."
    systemctl is-active "$service"
done
for loop — over files

Code: Select all

for f in /var/log/*.log; do
    echo "Log file: $f"
done
while loop — repeat until something changes

Code: Select all

count=1
while [ "$count" -le 3 ]; do
    echo "Attempt $count"
    count=$((count + 1))        # arithmetic uses $(( ))
done
Tip: Use a for loop when you know the list; use a while loop when you're waiting for a condition (e.g. "while the server isn't responding, keep retrying").

─────────────────────────────────────────

7 Functions — reusable blocks

A function is a named block of code you can call many times — it keeps scripts tidy and avoids repetition.

Code: Select all

#!/bin/bash

log() {
    echo "[$(date +%T)] $1"      # $1 is the first argument passed in
}

check_service() {
    if systemctl is-active --quiet "$1"; then
        log "$1 is running"
    else
        log "$1 is DOWN"
    fi
}

# Call them:
check_service sshd
check_service nginx
Tip: Inside a function, $1, $2, $3 are the arguments you passed when calling it. Define functions near the top, then call them lower down.

─────────────────────────────────────────

8 Putting it together — a practical example

A small backup script that ties in variables, a condition, a loop and a function — the kind of thing you'd then schedule with cron.

Code: Select all

#!/bin/bash
set -euo pipefail

backup_dir="/backup"
date_tag=$(date +%F)

log() { echo "[$(date +%T)] $1"; }

# Make sure the destination exists
if [ ! -d "$backup_dir" ]; then
    mkdir -p "$backup_dir"
    log "Created $backup_dir"
fi

# Back up several folders
for dir in /etc /var/www /home; do
    name=$(basename "$dir")
    log "Backing up $dir ..."
    tar czf "$backup_dir/${name}-${date_tag}.tar.gz" "$dir"
done

log "Backup complete"
Then schedule it to run daily at 2am:

Code: Select all

crontab -e
# add this line:
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Tip: The ">> /var/log/backup.log 2>&1" part saves both normal output and errors to a log file, so you can see what happened on a job that ran while you were asleep.

─────────────────────────────────────────

Quick Reference Cheat Sheet
  • Edit cron — crontab -e
  • List cron — crontab -l
  • Cron format — min hour day month weekday command
  • One-time job — echo "cmd" | at now + 1 hour
  • List at jobs — atq ; remove — atrm N
  • Shebang — #!/bin/bash
  • Make runnable — chmod +x script.sh
  • Variable — name="value" ; read with "$name"
  • Command output — today=$(date +%F)
  • Condition — if [ -f "$f" ]; then ... fi
  • Number test — [ "$n" -gt 5 ]
  • for loop — for x in a b c; do ... done
  • while loop — while [ cond ]; do ... done
  • Function — name() { ...; } then call: name arg
  • Arithmetic — $((a + b))
─────────────────────────────────────────

What's the most useful thing you've automated with cron or a shell script? Drop your favourite one-liner or script below.