Read

Module 6 · Processes and jobs

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.

ActionHowEffect
Start in backgroundcmd &Runs; prompt returns at once
Pause the foreground jobCtrl-ZStopped (STAT T), prompt returns
Resume in backgroundbg, bg %2Like having typed &
Bring to foregroundfg, fg %1Shell waits for it again
Interrupt the foreground jobCtrl-CSends SIGINT; usually ends it
Wait for a jobwait, wait $!Blocks, returns its exit status

Commands in this lesson

CommandWhat it does
cmd &Run cmd in the background; prints `[job] PID`.
jobsList this shell's background and stopped jobs.
fg %1Bring job 1 to the foreground.
bg %1Resume stopped job 1 in the background.
echo $!PID of the last background job.
wait $!Wait for that job and take its exit status.
kill %2Signal a job by job number.

Quiz

  1. 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
  2. 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
  3. What does `wait $!` return in `$?`?

    • Always 0
    • The exit status of the background job it waited for
    • The job's PID
  4. 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
  5. Which key combination ends the foreground job rather than pausing it?

    • Ctrl-Z
    • Ctrl-C
    • Ctrl-D

Practice

  1. Start `sleep 2000` in the background so you get your prompt back immediately.

  2. Start `sleep 2000` in the background and, on the same line, write its PID (from `$!`) into `/root/lab/l54/bgpid.txt`.

  3. 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.