Job control

Before graphical environments were common-place, job control was essential for working with multiple programs at the same time. Even in a graphical environment, job control can be a huge convenience for working with multiple programs without the need for a large number of open windows.

Foreground and background

To understand job control, it is useful to begin with foreground and background tasks. Generally, every program that runs is a foreground task. I might type ls, then edit a file, then rm *.bak. Each program, as a foreground task, writes its output to the screen and accepts input from the keyboard.

Sometimes we might want to run a program that we know is going to take a long time to complete. For example, we may have lost a file somewhere on the system called needle.txt. To find it, we could issue a find command, find / -name needle.txt -print, but searching the entire filesystem may take several minutes. Rather than wait, it makes sense to run this as a background task.

Example 9-3. Running a background task


$ find / -name needle.txt -print >list.txt 2>/dev/null &

Here, the find command is seen at the beginning of the line. The remaining parts of the line, in order, are:

>list.txt

Tells the shell to put the output of this command into a file. Since we are running the command in the background, we don't want the output to just go to the terminal where it would be interleaved with the output from other programs we are running. We can look in this file for the results when the program finishes.

2>/dev/null

Tells the shell that any error output should be put into /dev/null (effectively ignored).

&

Tells the shell to run this program in the background. A new prompt will immediately appear without waiting for the program to finish. The find program will continue running in the background until completion.

Working with jobs

Job control can be used for more than running programs in the background. It can also be used to conveniently switch back and forth between programs. For example, imagine you are making a file called calc.txt to put various calculations into. A very crude (but simple) way to create such a file is using the cat command.

Example 9-4. Suspending a task


$ cat > calc.txt
The sum 1+1 is equal to 2.
Zero plus any number is itself.
^Z
[1]+  Stopped                 cat >calc.txt

Where the ^Z is shown, the user pressed Ctrl-Z. This will suspend the execution of most programs and present another shell prompt that can be used to run more programs. Perhaps we need to calculate the value for 10!. At the shell prompt, we could type:

Example 9-5. Running and suspending a second task


$ calc
C-style arbitrary precision calculator (version 2.11.5t4.5)
Calc is open software. For license details type:  help copyright
[Type "exit" to exit, or "help" for help.]

> 10!
        3628800
> ^Z
[2]+  Stopped                 calc

Now there are two stopped jobs. We can list the current jobs using the jobs command.

Example 9-6. Listing jobs


$ jobs
[1]-  Stopped                 cat >calc.txt
[2]+  Stopped                 calc

The fg command will bring a job into the foreground. Without arguments, fg will attempt to guess what the ``current job'' is and bring that to the foreground. You can specify a particular job using the percent sign (%) and the job number. For example:

Example 9-7. Resuming a job


$ fg %1
cat >calc.txt
The value for 10! is 3628800.
^D

The fg command restarted the cat job, and it ran until we typed Ctrl-D (the symbol that marks the end of input under unix). If there were many calculations to complete, we could just as easily have used Ctrl-Z to suspend again and brought the calculator back to the foreground in the same fashion.

Since we are finished using the calculator, we can simply close the calc program. Typing fg will bring it to the foreground (it is now the current job, since the other program has finished), and we can exit normally. If there were some problem with the calc program, we could also kill it with kill %2 or kill -9 %2 as necessary.

Putting a foreground job into the background

Starting a job in the foreground only to discover that it should go in the background is a fairly common occurrence. To move the task to the background, simply suspend it with Ctrl-Z and then use the bg command. For example:

Example 9-8. Moving a job to the background


$ xterm
^Z
[1]+  Stopped                 xterm
$ bg %1
[1]+ xterm &
$

This xterm was accidently started in the foreground and then moved to the background. It will now show on the job list as Running, and it can be moved back into the foreground if necessary with the fg command.