Foreground, Background, Jobs, nohup, and tmux
Control shell jobs safely, understand terminal ownership and hangups, and choose between backgrounding, nohup, tmux, and real service supervision.
Learning objectives
By the end of this lesson
- Distinguish a shell job from a process and a foreground process group.
- Use
&,jobs,fg,bg, and job specifications safely. - Explain why terminal disconnects can terminate or disrupt ad hoc workloads.
- Use
nohupandtmuxappropriately while recognizing their limitations. - Choose a service manager or scheduler for durable production workloads.
1. Foreground means control of the terminal
Interactive shells organize pipelines into jobs and process groups. The terminal has one foreground process group at a time. That group receives terminal-generated signals such as interrupt from Ctrl+C, suspend from Ctrl+Z, and input from the keyboard. A background process group can continue running but normally cannot read from the controlling terminal.
flowchart TB T["Terminal and TTY driver"] --> F["Foreground process group"] T -. input and Ctrl+C .-> F S["Interactive shell"] -->|launches pipelines| F S --> B1["Background job group 1"] S --> B2["Stopped job group 2"] F -->|Ctrl+Z / SIGTSTP| B2 S -->|fg| F S -->|bg| B2
A job can contain several processes, such as a pipeline. Job identifiers like %1 are shell-local references, while PIDs identify individual processes system-wide within a PID namespace.
2. Launch and inspect shell jobs
# Start a background job and capture its last process PID.
sleep 300 &
pid=$!
# Show jobs known to this shell, including PIDs.
jobs -l
# Refer to jobs by shell job specification.
# fg %1 # Bring job 1 to the foreground.
# bg %1 # Continue a stopped job in the background.
# Send TERM to the controlled process and collect its status.
kill -TERM "$pid"
wait "$pid" 2>/dev/null || truejobs only knows jobs created by the current shell and retained in its job table. A process can exist without being a current-shell job. Conversely, one job can represent a multi-process pipeline. Use jobs -l, ps, and process groups together when precision matters.
Job IDs are interactive shell state and can change as jobs start or finish. Scripts should capture PIDs, use wait semantics, or delegate lifecycle to a supervisor.
3. Stopped is not terminated
Pressing Ctrl+Z usually sends SIGTSTP to the foreground process group. The process remains in memory but is not scheduled until continued. bg continues it in the background; fg continues it and restores foreground terminal control.
# Controlled demonstration without keyboard interaction.
sleep 300 &
pid=$!
kill -TSTP "$pid"
ps -o pid,ppid,pgid,tpgid,stat,comm,args -p "$pid"
kill -CONT "$pid"
ps -o pid,ppid,pgid,tpgid,stat,comm,args -p "$pid"
kill -TERM "$pid"
wait "$pid" 2>/dev/null || trueA stopped deployment, migration, or terminal utility may appear “hung” while actually waiting in state T. Check state and terminal/job context before escalating.
4. Disconnects, SIGHUP, and nohup
When a terminal closes, the session and shell may send SIGHUP to associated jobs. Programs may also fail later because standard input, output, or error still points to a closed terminal. nohup arranges for the launched command to ignore SIGHUP and commonly redirects terminal output.
lab="$HOME/devops-academy/linux/chapter08/lesson03"
mkdir -p "$lab"
nohup bash -c '
for n in 1 2 3 4 5; do
printf "%s step=%s\n" "$(date --iso-8601=seconds)" "$n"
sleep 2
done
' > "$lab/nohup-demo.log" 2>&1 &
pid=$!
printf 'nohup_pid=%s\n' "$pid"
wait "$pid"
cat "$lab/nohup-demo.log"nohup is useful for a small ad hoc command, but it does not provide restart policy, structured logging, dependency ordering, health checks, resource limits, startup on boot, or ownership records. It is not a production service manager.
5. tmux preserves an interactive workspace
tmux is a terminal multiplexer. A tmux server owns sessions containing windows and panes. Your terminal attaches as a client and can detach without terminating the session. This is valuable for remote administration, long interactive investigations, and training labs.
tmux new -s incidentStart a named sessiontmux list-sessionsSee active sessionsCtrl+b dDisconnect client, preserve sessiontmux attach -t incidentReturn to the sessiontmux capture-pane -pExport visible pane historytmux kill-session -t incidentTerminate the named sessionA tmux session protects against client disconnects, not host reboot or service failure. Apply access control carefully because anyone who can access the tmux server socket may control sessions and view terminal content.
6. Choose the right lifecycle owner
Short interactive task
Use when you remain connected and can monitor or wait for completion.
Small ad hoc detached command
Use with explicit input/output paths and a cleanup plan.
Interactive remote session
Use when you need to detach and later resume a terminal workflow.
Durable operational workload
Use for restart, boot integration, identity, logs, resources, dependencies, and auditability.
CI jobs should be owned by the CI runner, scheduled work by a scheduler or systemd timer, and long-running services by a service manager. Avoid hiding important production work inside personal shells.
7. Hands-on lab: observe jobs, groups, and detachment
Start a background pipeline, inspect its process group, stop and continue it, then run a detached tmux session when tmux is available.
lab="$HOME/devops-academy/linux/chapter08/lesson03"
mkdir -p "$lab"
# Start a pipeline as a shell job.
{ while :; do date --iso-8601=seconds; sleep 2; done; } \
| sed -u 's/^/pipeline /' > "$lab/pipeline.log" &
pid=$!
jobs -l
ps -o pid,ppid,pgid,sid,tpgid,stat,comm,args --ppid "$$"
kill -TSTP "$pid"
sleep 1
ps -o pid,ppid,pgid,sid,tpgid,stat,comm,args -p "$pid"
kill -CONT "$pid"
sleep 3
kill -TERM "$pid"
wait "$pid" 2>/dev/null || true
tail "$lab/pipeline.log"
# Optional tmux demonstration.
if command -v tmux >/dev/null; then
session="da-ch8-l3-$$"
tmux new-session -d -s "$session" \
"printf 'session started at %s\\n' '\$(date --iso-8601=seconds)'; sleep 5; printf 'done\\n'"
tmux list-sessions
sleep 6
tmux capture-pane -p -t "$session" > "$lab/tmux-output.txt" || true
tmux kill-session -t "$session" 2>/dev/null || true
cat "$lab/tmux-output.txt"
fiVerification checklist
8. Common mistakes
Assuming & survives logout
Backgrounding changes terminal foreground placement; it does not establish durable supervision.
Leaving output attached to a terminal
A detached command can block or fail when writing to a closed terminal. Redirect all streams intentionally.
Running production services in tmux
tmux is an interactive workspace, not a restart-capable service manager.
Confusing stopped with dead
A stopped job still owns memory, descriptors, locks, and other resources.
9. Knowledge check
Question 1. What receives terminal-generated Ctrl+C?
Question 2. What does nohup not provide?
Question 3. Why is tmux useful over SSH?
10. Summary
Shell job control is built around jobs, process groups, sessions, and the controlling terminal. Backgrounding, stopping, continuing, nohup, and tmux solve different interactive problems. Durable services and scheduled workloads need a real lifecycle owner such as systemd, a scheduler, or a CI runner—not a forgotten personal shell.
11. Further reading
- Bash Reference Manual sections on job control and signals.
jobs(1p),nohup(1),setsid(1), andtmux(1).termios(3)andcredentials(7)for terminal, session, and process-group concepts.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.