Background jobs: &, jobs, fg, bg
Run a command without waiting for it, keep track of your jobs, pause one with Ctrl-Z, bring it back with fg, and let the shell wait for it with wait.
What you will learn
- Start a command in the background with `&` and read the `[job] PID` line.
- List, resume and bring back jobs with `jobs`, `bg`, `fg` and `%N`.
- Use `$!` and `wait` to follow a background job from the same shell.
The shell waits, unless you tell it not to
Normally the shell starts a command, hands it the terminal and waits until it exits before printing the next prompt. That command is the foreground job. Append an ampersand, &, and the shell starts the command and comes straight back to you: the command runs in the background, sharing the screen but not the keyboard. The shell answers with two numbers, [1] 1012: the job number in brackets, which is local to this shell, and the PID, which is system-wide.
~% sleep 300 &
[1] 1012
~% echo $!
1012
~% sleep 400 &
[2] 1015
~% jobs
[1] Running sleep 300
[2] Running sleep 400
~% kill %1
~% jobs
[1] Terminated sleep 300
[2] Running sleep 400
jobs lists the background jobs of *this shell* with their number, state and command line. A job number prefixed with % names the job in other commands: kill %1, fg %2, wait %1. The variable $! holds the PID of the most recent background job, which is what scripts save when they need to signal or wait for it later. Remember from lesson 51: a job is just a process that happens to have been started with &; ps shows it like any other.
Ctrl-Z, fg and bg
Forgot the &? You do not have to kill the command and start over. Press Ctrl-Z and the foreground job is stopped: frozen, still in memory, with STAT T in ps. The shell prints [1]+ Stopped sleep 300 and gives you a prompt. From there, bg resumes the job in the background, as if you had typed & from the start, and fg resumes it in the foreground and makes the shell wait again. Both take %N; with no argument they act on the most recent job, the one jobs marks with +.
Ctrl-C is different: it sends SIGINT to the foreground job and normally kills it (lesson 55 covers signals). Ctrl-Z pauses; Ctrl-C ends. Neither reaches a background job, because the keyboard belongs to the foreground only. That is also why a background job that tries to *read* from the keyboard gets stopped automatically with Stopped (tty input): bring it to the foreground with fg to answer it.
wait
~% sleep 5 &
[1] 1020
~% wait $!
~% echo $?
0
~% (sleep 2; exit 3) &
[1] 1023
~% wait %1; echo "exit status $?"
exit status 3
wait blocks until a background job finishes and then returns *its* exit status, which is how a script can start several slow commands in parallel and collect the results. wait alone waits for every job; wait $! or wait %1 waits for one. In the lab's single shell it is mostly a way to confirm the idea: the shell's own $? after wait is the exit status of the child.
| Action | How | Effect |
|---|---|---|
| Start in background | cmd & | Runs; prompt returns at once |
| Pause the foreground job | Ctrl-Z | Stopped (STAT T), prompt returns |
| Resume in background | bg, bg %2 | Like having typed & |
| Bring to foreground | fg, fg %1 | Shell waits for it again |
| Interrupt the foreground job | Ctrl-C | Sends SIGINT; usually ends it |
| Wait for a job | wait, wait $! | Blocks, returns its exit status |
Commands in this lesson
| Command | What it does |
|---|---|
cmd & | Run cmd in the background; prints `[job] PID`. |
jobs | List this shell's background and stopped jobs. |
fg %1 | Bring job 1 to the foreground. |
bg %1 | Resume stopped job 1 in the background. |
echo $! | PID of the last background job. |
wait $! | Wait for that job and take its exit status. |
kill %2 | Signal a job by job number. |
Quiz
After `sleep 300 &` the shell prints `[1] 1012`. What is 1012?
- The job number
- The PID of the sleep process
- The number of seconds left
You started a long command without `&`. How do you get it into the background without restarting it?
- Ctrl-C, then type it again with &
- Ctrl-Z to stop it, then `bg`
- Type `&` on its own line
What does `wait $!` return in `$?`?
- Always 0
- The exit status of the background job it waited for
- The job's PID
Can another terminal use `fg %1` to grab your background job?
- Yes, job numbers are global
- No: job numbers exist only inside the shell that started the job
- Only if it is root
Which key combination ends the foreground job rather than pausing it?
- Ctrl-Z
- Ctrl-C
- Ctrl-D
Practice
Start `sleep 2000` in the background so you get your prompt back immediately.
Start `sleep 2000` in the background and, on the same line, write its PID (from `$!`) into `/root/lab/l54/bgpid.txt`.
A `sleep 2000` is running as job 1 of your shell. Bring it to the foreground (then Ctrl-C to end it).
Open this lesson in the app to do the tasks in a real Linux machine and have them checked.