Background and Foreground: &, jobs, fg, nohup

Sometimes you start a command and realize it’ll take an hour. Sometimes you SSH in, start a server, and the moment you log out it dies. Bash gives you precise control over which processes run in the foreground (blocking your terminal) versus the background (released back to the prompt) — and how to survive a disconnect.

Run a command in the background

Append &:

./long-task.sh &
# [1] 12345         ← job number 1, PID 12345
# back to prompt immediately

Output (stdout/stderr) still goes to your terminal — usually messy. Redirect it:

./long-task.sh > task.log 2>&1 &

See your jobs

jobs              # list jobs in current shell
jobs -l           # also show PIDs
jobs -p           # only PIDs

Foreground / background a running job

fg                # bring most recent background job to foreground
fg %1             # bring job number 1 to foreground
bg                # resume most recent stopped job in background
bg %2             # resume job 2 in background

Suspend a foreground command

While a command is running in the foreground:

Ctrl+Z            # suspend (process is stopped, not killed)

Then push it to background:

bg                # continue it in background
fg                # bring it back to foreground

Common workflow: start vim, hit Ctrl+Z, do something in shell, type fg to go back to vim where you left off.

Survive a disconnect

If you SSH in and run something, then disconnect, your shell process gets a SIGHUP — which kills your background jobs by default. Three ways to survive:

nohup

nohup ./long-task.sh &
# output goes to nohup.out unless you redirect

The nohup command makes the process ignore SIGHUP. It will keep running after logout.

disown (after the fact)

Started a job and forgot to nohup it? Disown after the fact:

./long-task.sh &
disown                  # detach from current shell

tmux or screen (the real answer)

The proper tool for “I want to run something on a server and reconnect later” is tmux (or the older screen). It’s a terminal multiplexer — your sessions live independently of any SSH connection.

# start a named session
tmux new -s mywork

# do whatever you want; everything keeps running

# detach: press Ctrl+b then d
# you're back in your shell, but tmux is still running

# reconnect anytime — even from a different machine
tmux attach -t mywork

# list sessions
tmux ls

tmux is the answer to “I started something on a server and want to come back to it tomorrow.”

Kill background jobs

kill %1                 # kill job 1
kill -9 %1              # force kill
kill 12345              # kill by PID
killall firefox         # kill all processes named firefox

Common patterns

# Run a build in background, log everything
make all > build.log 2>&1 &

# Wait for ALL background jobs to finish
./job1 &
./job2 &
./job3 &
wait
echo "all done"

# Run a long thing on a server and keep it running
ssh server
tmux
./long-task.sh
# Ctrl+b d to detach
exit            # SSH session ends; tmux session keeps running

# Reconnect later
ssh server
tmux attach

Common mistakes

  • Forgetting to redirect output — your background job spams the terminal.
  • Using nohup when you should use tmux — for anything interactive, tmux is better.
  • fg with no jobs — “bash: fg: current: no such job”.
  • Closing the terminal with running foreground processes — they all die. Suspend with Ctrl+Z + bg + disown first, or use tmux.

What to learn next

Background processes get sent signals (SIGHUP, SIGTERM, SIGKILL) when you kill them. Understanding signals — what each one does and which to use — is the next topic.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *