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 || true
jobs 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 || true
A 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 session
tmux list-sessionsSee active sessions
Ctrl+b dDisconnect client, preserve session
tmux attach -t incidentReturn to the session
tmux capture-pane -pExport visible pane history
tmux kill-session -t incidentTerminate the named session
A 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"
fi
Verification 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.