Bash Process Management

A process is a running program. Every command you start creates a process with its own number. Process management means watching, pausing, moving, and stopping those programs. These skills help you run long tasks in the background and fix programs that stop responding.

Foreground and Background

A foreground process holds the terminal until it finishes. A background process runs quietly while you continue typing new commands. A kitchen offers a good picture: the cook stirs one pot by hand (foreground) while a slow cooker works alone (background).

  Terminal
  +-------------------------------------------+
  |  Foreground:  nano notes.txt   (you type) |
  |                                           |
  |  Background:  [1] backup.sh    (runs)     |
  |               [2] sleep 300    (runs)     |
  +-------------------------------------------+

Start a Process in the Background

Add an ampersand at the end of a command:

sleep 120 &

Output:

[1] 4821

The number in brackets is the job number. The second number is the process ID (PID).

List Jobs in the Current Terminal

jobs
[1]+  Running    sleep 120 &

Move Jobs Between Foreground and Background

fg %1        # bring job 1 to the foreground
bg %1        # resume job 1 in the background

Pause a foreground program with Ctrl+Z. The program freezes and appears in the job list as "Stopped". Type bg to let it continue in the background.

See All Running Processes

The ps Command

ps              # processes in the current terminal
ps aux          # every process on the system

Important columns in ps aux include USER, PID, %CPU, %MEM, and COMMAND.

The top Command

top

Top shows a live, refreshing table sorted by CPU use. Press q to quit. The tool htop offers a friendlier display and may need a separate install.

Find a Process

pgrep sleep
pgrep -l bash
ps aux | grep "[b]ackup"

The pgrep command prints process IDs that match a name. The square brackets around the first letter in the last line stop grep from listing itself.

Stop a Process

The kill command sends a signal to a PID:

kill 4821          # polite stop (SIGTERM)
kill -9 4821       # forced stop (SIGKILL)
pkill sleep        # stop by name
killall sleep      # stop every process with that name

Start with the polite request. A program that ignores it needs the forced option. The forced signal gives the program no chance to save its work.

Keep a Process Alive After Logout

Closing a terminal sends a hangup signal to its jobs. The nohup command blocks that signal:

nohup ./long_task.sh &

Output goes into a file named nohup.out by default. Choose a different file with redirection:

nohup ./long_task.sh > task.log 2>&1 &

The disown command detaches a running job from the terminal in a similar way.

Wait for Background Jobs

A script can start several tasks together and wait for all of them:

#!/bin/bash
echo "Starting three tasks"

sleep 3 &
sleep 2 &
sleep 4 &

wait
echo "All tasks finished"

The three tasks run at the same time, so the script waits about four seconds instead of nine.

Read the PID of the Last Background Job

#!/bin/bash
sleep 30 &
pid=$!
echo "Background PID: $pid"
kill $pid
echo "Job stopped"

The variable $! holds the PID of the most recent background job. The variable $$ holds the PID of the script itself.

Change Priority With nice

A priority value from -20 (highest) to 19 (lowest) controls how much CPU time a process receives. Start a heavy task with low priority so other programs stay fast:

nice -n 10 ./heavy_task.sh
renice -n 5 -p 4821

Raising priority above zero requires administrator rights.

Check Whether a Process Runs

#!/bin/bash
if pgrep -x "nginx" > /dev/null; then
  echo "Nginx is running"
else
  echo "Nginx is stopped"
fi

The -x option matches the exact name. The redirect to /dev/null hides the PID output.

Key Takeaways

  • Add & to run a command in the background.
  • jobs, fg, and bg manage jobs in the current terminal.
  • ps, top, and pgrep show and find processes.
  • kill stops a process, and kill -9 forces the stop.
  • nohup keeps a job alive after the terminal closes.
  • wait pauses a script until background jobs end.