Processes & Job Control
Every program running on Linux is a process with a PID, a parent, memory and a life cycle. Learn to inspect processes with ps and pgrep, terminate them with kill and pkill, manage foreground and background jobs, tune priority with nice and renice, and understand how daemons stay alive in the background.
What is this?
A process is a running instance of a program — the kernel's unit of work, with its own PID (process ID), a parent (PPID), memory space and state. When you run ls, the shell forks a child and execs it into ls; the kernel then schedules it onto a CPU. Understanding processes is how you answer 'what is eating my CPU?' and 'why won't this service die?' in production — and how every container, which is really just a group of processes in namespaces, behaves.
Why do you need it?
- Find the culprit: ps and top show exactly which process is burning CPU, memory or disk.
- Kill stuck or runaway jobs cleanly instead of rebooting the whole server.
- Run long tasks in the background with jobs, fg and bg while keeping your terminal usable.
- Control priority with nice and renice so a critical database outcompetes a noisy log parser.
- Understand daemons and systemd: a service is just a supervised process with a defined life cycle.
Mental model
A busy restaurant kitchen
Linux process management
The head chef (systemd, PID 1) assigns each cook (process) a ticket number (PID) and a station. The chef who hands out the ticket is the parent process. kill is a polite 'please stop' (SIGTERM) — the cook finishes the plate. kill -9 is security yanking the cook out mid-move with no time to wash up.
How it works
- The shell calls fork(), which clones the current process into a near-identical child with a fresh PID whose PPID points back to the parent.
- The child then calls exec() to replace its code and data with the program you actually asked for — same process, new program.
- The kernel scheduler divides CPU time between all runnable processes, preempting them so one runaway cannot starve the machine.
- When a process exits it leaves an exit status; the parent must wait() to reap it, otherwise the process becomes a zombie. If the parent dies first, PID 1 reparents and reaps the orphan.
- Signals are how the kernel asks a process to act: SIGTERM (15) requests a graceful shutdown, SIGKILL (9) is delivered by the kernel and cannot be caught or ignored.
The life cycle of a Linux process from shell command to exit.
Key commands
ps auxShow every process with user, CPU, memory and the full command line.
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 169292 14256 ? Ss 08:10 0:02 /sbin/init root 42 0.0 0.0 15576 4120 ? S 08:10 0:00 /usr/sbin/sshd appuser 1101 0.3 1.2 892332 102456 ? Ssl 08:12 0:45 node /app/server.js
ps -p 1101 -o pid,ppid,%cpu,%mem,cmdInspect one PID and its parent, CPU and memory in a clean table.
PID PPID %CPU %MEM CMD 1101 972 0.3 1.2 node /app/server.js
pgrep -x nginxFind the PID of a process by exact name match.
4567
pidof nginxPrint all PIDs for a program name (handy with multiple workers).
4568 4569 4567
kill 4567Send SIGTERM (the default) — a polite request to shut down gracefully.
kill -9 4567Send SIGKILL — the kernel terminates the process immediately; it cannot catch this.
pkill -f 'node server.js'Kill every process whose full command line matches the pattern.
jobs -lList the shell's background and suspended jobs with their PIDs.
[1]+ Running sleep 300 & [2]- Stopped vim notes.txt
fg %1Bring job 1 back to the foreground so you can interact with it.
bg %2Resume a suspended job as a background process.
nice -n 10 ./backup.shStart a process with a lower priority (higher nice value = nicer = lower priority).
renice -n 5 -p 4567Change the nice value of an already-running process.
Examples
Start, background, inspect and kill a process
# Start a long-running process in the backgroundsleep 300 & # See it listed as a job with its PIDjobs -l # Find its PID by namepgrep -x sleep # See exactly what it is doingps aux | grep sleep # Ask it to stop, then confirm it is gonekill <PID>ps aux | grep sleepThe & puts sleep in the background so your shell stays usable. jobs lists the session's background jobs, pgrep finds the PID, and kill sends SIGTERM by default. Because sleep has nothing to clean up it exits instantly; a busy web server may need SIGKILL (kill -9) instead.
In production
- Every cloud VM, container and Kubernetes node is a tree of processes — ps/pgrep/kill work identically inside a pod as on a bare-metal host.
- Debugging a slow deploy starts with top and ps aux --sort=-%cpu to find the process causing the latency.
- pkill -f 'command pattern' terminates all workers of an app (e.g. stale CI agents) without hunting for PIDs.
- nohup or setsid keeps long jobs alive across SSH disconnects — essential for overnight migrations and batch jobs.
- Priority tuning (nice/renice) protects latency-sensitive services like databases from batch jobs hogging the CPU.
Best practices
- Always try plain kill (SIGTERM) first and give the process a few seconds; use kill -9 only as a last resort.
- Verify what you kill: pgrep -f the pattern before pkill -f to avoid nuking unrelated processes.
- Confirm a kill worked with ps or pgrep rather than assuming — a process can respawn (e.g. systemd Restart=always).
- Use jobs -l to get the PID, not just the job number, when a job needs to be killed from another terminal.
- Prefer systemctl restart over kill for supervised services, and let systemd own their life cycle.
Common mistakes
- Reaching for kill -9 immediately — it skips cleanup, corrupting config files and databases that need to flush.
- Assuming PID 1 of a container is a shell: in containers the entrypoint process has PID 1 and killing it stops the container.
- Using pkill -f on a vague pattern like 'python' and killing the wrong processes.
- Killing a process by the PID of its parent or one of its workers and expecting the whole tree to stop.
Common issues
kill: (4567) - No such processThe PID is stale — the process already exited or you grabbed a worker PID that has since respawned.
Re-check with pgrep -x <name> or ps -p <PID> and kill the current PID.
bash: bg: %1: no such jobThe job number is wrong or that job already finished.
Run jobs to list the real job specifiers, then use the correct one (e.g. fg %2).
Background job dies when I close my SSH sessionThe shell sends SIGHUP to its jobs on logout, and the job did not ignore it.
Launch with nohup sleep 300 & or setsid sleep 300, or run disown %1 after backgrounding it.
Process will not die even after kill -9A process in uninterruptible kernel sleep (state D, blocked on disk/NFS I/O) cannot be killed until the I/O resolves.
Identify the I/O target with iostat and ps, fix the underlying disk or NFS issue; only then will the process die or complete.
Debugging tips
- ps aux --sort=-%cpu ranks processes by CPU use — the top row is usually the culprit.
- kill -l lists every signal name and number so you never guess a signal.
- A process stuck in the D (uninterruptible sleep) state is usually blocked on I/O — check iostat, not kill.
- Zombies are already dead: they show as Z and only disappear when their parent reaps them or systemd reparents them.
Interview checkpoint
Hands-on lab
- Launch a process in the background and track it as a shell job
- Suspend and resume jobs with Ctrl+Z, bg and fg
- Locate a process by name and PID with pgrep and ps
- Terminate a process gracefully with kill and forcefully with kill -9
- Verify the process is gone and the shell stays responsive
Manage a background job and kill it cleanly
15 min · intermediate
Quick quiz
What is a PID?
Which signal terminates a process gracefully and can be caught or ignored by the process?
The kill command without a signal number sends SIGKILL (kill -9).
What does pressing Ctrl+Z in a terminal do?
Which command shows every process with CPU and memory usage?
A stuck server process ignores kill <PID> for over ten seconds. What is your next step?
Cheat sheet
ps auxAll processes with CPU/memoryps -efAll processes (POSIX style)ps -p <PID> -o pid,ppid,%cpu,%mem,cmdOne PID, chosen columnsps aux --sort=-%cpuSorted by CPU usagepgrep -x nginxPID by exact namepidof nginxAll PIDs for a programkill <PID>SIGTERM (15), gracefulkill -9 <PID>SIGKILL, cannot be ignoredkill -STOP <PID>Suspend a running processkill -CONT <PID>Resume a suspended processpkill -f 'pattern'Kill by full command linekill -lList all signal namescommand &Run in the backgroundCtrl+ZSuspend the foreground jobjobs -lList jobs with PIDsfg %1Bring job 1 to the foregroundbg %1Resume job 1 in the backgroundnohup command &Survive logout (ignore SIGHUP)nice -n 10 ./backup.shStart with lower prioritynice -n -5 ./urgent.shStart with higher priority (root only)renice -n 5 -p <PID>Re-prioritise a running process