Background Commands

To wrap up our discussion of the interactive shell, let’s take a look at background commands. Any simple command or pipeline can be terminated with an & operator instead of a <newline> or semicolon, ;. In such instances, the command will be run in the background.

What does this mean, exactly? Well, the major difference is that normally the shell waits for its current command to finish executing before it reads the next line of input. When a command is instead run in the background, the shell does not wait for it. Instead, it places that command (or pipeline) in its own process group, which the shell calls a job. The shell keeps track of all its background processes, which can be listed with the jobs command:

$ jobs
[1]-  Running                 sleep 5 &
[2]+  Running                 sleep 10 &
[3]   Stopped                 vim

Each job is assigned a jobid, shown as the numbers in the square brackets above. The ‘+’ indicates the current job, and the ‘-’ indicates the job that will become the current job after the ‘+’ job leaves job control by exiting or being moved into the foreground.

If a job is stopped or running in the background, the fg command can bring it back into the foreground so that the user can interact with it again. If not provided arguments, the current job will be affected; otherwise, a specific job can be targeted with %jobid (e.g. fg %3 to bring vim into the foreground).

If a job is running in the foreground, pressing ctrl+z will cause it to be stopped and placed in a background job, returning control to the shell. The user can then use the bg command to send that job a continuation signal so that it continues running in the background. Let’s look at a simple example of running sleep in the foreground, stopping it, and then allowing it to continue running in the background,

$ sleep 100
^Z
[1]+  Stopped                 sleep 100
$ bg
[1]+  sleep 100 &
$ jobs
[1]+  Running                 sleep 100 &

There aren’t many reasons to place a sleep process in the background, but imagine you start a long-running program (such as recursively deleting a lot of files with rm), and then realise you want to continue using the shell without having to stop and rerun the current program in the background with &. Simply stop it, and move it to the background, freeing up the shell for you to continue using!

When a background process attempts to read input from the terminal, it will receive a signal that causes it to stop running, and you will be notified. In the following example, the sed utility tries to read from stdin, repeating its output to stdout, replacing ‘H’ with ‘J’. Since it’s run in the background with &, it is immediately stopped, and must be returned to the foreground with fg in order to continue running:

$ sed 's/H/J/' &
[1] 2933778
[1]+  Stopped                sed 's/H/J/'
$ fg
Hello World!
Jello World!

Notice when we run a command in the background, the shell prints its jobid and process id before the next prompt:

$ sleep 100 &
[1] 387538
$ sleep 10 &
[2] 387539
$ jobs
[1]-  Running               sleep 100 &
[2]+  Running               sleep 10 &