Table of Contents

Shell Processes

Background and Foreground

Run commands in the background by appending & to allow the shell prompt to return immediately. Use fg and bg to move jobs between foreground and background.

# Run in background (shell returns immediately)
long_running_task &
 
# List all jobs
jobs
 
# Bring last job to foreground
fg
 
# Bring specific job to foreground (e.g., job 1)
fg %1
 
# Resume a suspended job in background
bg
 
# Run command and get its PID
curl http://example.com &
echo $!  # Print the background job PID

Manage multiple background jobs:

# Start multiple background jobs
sleep 100 &   # Job 1
sleep 200 &   # Job 2
sleep 300 &   # Job 3
 
# List all jobs with status
jobs -l       # Show job numbers and PIDs
 
# Bring job 2 to foreground
fg %2
 
# Kill job 1
kill %1
 
# Wait for all background jobs
wait
 
# Wait for specific job
wait $!

Job Control

Use Ctrl+Z to suspend (pause) a foreground job without terminating it. The job can be resumed later with fg or bg.

# Suspend current foreground job (Ctrl+Z)
# [1]+ Stopped    vim myfile.txt
 
# Resume in background
bg
 
# List suspended job
jobs
# [1]+ Stopped    vim myfile.txt
 
# Resume in foreground
fg %vim   # Bring vim back to foreground

Prevent shell exit from terminating background jobs using disown or nohup:

# Start a long task
backup.sh &
 
# Disown the job (it persists after shell exits)
disown %1
 
# Alternative: use nohup to ignore hangup signals
nohup long_task.sh &
 
# Output redirected to nohup.out by default
nohup long_task.sh > task.log 2>&1 &

Traps and Signals

Use trap to run code when the shell receives a signal. Common signals include SIGINT (Ctrl+C), SIGTERM (termination request), SIGHUP (hangup), and SIGKILL (cannot be trapped).

# Trap Ctrl+C and exit cleanly
trap 'echo "Interrupt caught"; exit' INT
 
# Trap multiple signals
trap 'cleanup' INT TERM EXIT
 
cleanup() {
    echo "Cleaning up..."
    rm -f "$tmpfile"
    kill "$bg_job" 2>/dev/null
}
 
# Temporary file that gets deleted on exit
tmpfile=$(mktemp)
trap "rm -f '$tmpfile'" EXIT
# ... use tmpfile ...

Common signals and their uses:

# Log script activity
log_file="/tmp/script.log"
trap 'echo "Script interrupted at $(date)" >> "$log_file"' INT
 
# Save state before exit
state_file="/tmp/app_state"
trap 'save_state' EXIT
 
save_state() {
    echo "Current state: $counter" > "$state_file"
}
 
# Cleanup on error
trap 'echo "Error on line $LINENO"; exit 1' ERR
 
# Wait for background job and trap termination
long_task &
pid=$!
trap 'kill $pid 2>/dev/null' TERM EXIT
wait $pid

Use kill -l to list all available signals:

# List all signals
kill -l
 
# Send specific signal to process
kill -SIGTERM $pid   # Request termination
kill -SIGKILL $pid   # Force kill (cannot be trapped)
kill -SIGSTOP $pid   # Suspend (like Ctrl+Z)
kill -SIGCONT $pid   # Resume suspended process