start page | rating of books | rating of authors | reviews | copyrights

Book HomeBook TitleSearch this book

8.2. Job Control

Why should you care about process IDs or job numbers? Actually, you could probably get along fine in your Unix life without ever referring to process IDs (unless you use a windowing workstation -- as we'll see soon). Job numbers are more important, however: you can use them with the shell commands for job control.

You already know the most obvious way to control a job: you can create one in the background with &. Once a job is running in the background, you can let it run to completion, bring it into the foreground, or send it a message called a signal.

8.2.1. Foreground and Background

The built-in command fg brings a background job into the foreground. Normally this means that the job has control of your terminal or window and therefore is able to accept your input. In other words, the job begins to act as if you typed its command without the &.

If you have only one background job running, you can use fg without arguments, and the shell brings that job into the foreground. But if you have several jobs running in the background, the shell picks the one that you put into the background most recently. If you want a different job put into the foreground, you need to use the job's command name, preceded by a percent sign (%), or you can use its job number, also preceded by %, or its process ID without a percent sign. If you don't remember which jobs are running, you can use the jobs command to list them.

A few examples should make this clearer. Let's say you created three background jobs as above. If you type jobs, you see this:

[1]   Running                  fred &
[2] - Running                  bob &
[3] + Running                  dave | george &

jobs has a few interesting options. Besides the job status, jobs -l also lists process group IDs:

[1]   2349      Running                  fred &
[2] - 2367      Running                  bob &
[3] + 2382      Running                  dave | george &

How does all this work? Every time you run a job, the process(es) in the job are put into a new process group. Each process in a process group, besides its unique process ID number, also has a process group ID. The process group ID is the same as the process ID of the process group leader, which is one of the processes invoked as part of the job. (The last one in the pipeline, in fact.) The numbers that the shell prints are actually the process group IDs. (Note that for job 3, there are two processes, but only one number.)

Now, your terminal device, be it a real serial port or a pseudo-terminal such as you get in a windowing system or telnet session, also has a process group ID number. Processes whose process group ID matches that of the terminal "own" the terminal, in the sense that they are allowed to read input from it. In brief, job control works by setting the process group of the terminal to be the same as the process group of the current job. (There are lots more technical details, including the idea of a "session" introduced by POSIX, but those details aren't necessary for understanding the day-to-day use of job control.)

The -p option tells jobs to list only process group IDs:

$ jobs -p
2349
2367
2382

This could be useful with command substitution; see Task 8-1 later in this chapter. Finally, the -n option lists only those jobs whose status has changed since the shell last reported it -- whether with a jobs command or otherwise.

If you type fg without an argument, the shell puts dave | george in the foreground, because it was put in the background most recently. But if you type fg %bob (or fg %2), bob will go in the foreground.

You can also refer to the job most recently put in the background by %+. Similarly, %- refers to the background job invoked next-most recently (bob in this case). That explains the plus and minus signs in the above: the plus sign shows the most recently invoked job; the minus sign shows the next most recently invoked job.[113]

[113] This is analogous to ~+ and ~- as references to the current and previous directory; see the footnote in Chapter 7. Also: %% is a synonym for %+.

If more than one background job has the same command, then %command will disambiguate by choosing the most recently invoked job (as you'd expect). If this isn't what you want, you need to use the job number instead of the command name. However, if the commands have different arguments, you can use %?string instead of %command. %?string refers to the job whose command contains the string. For example, assume you started these background jobs:

$ bob pete &
[1]     189
$ bob ralph &
[2]     190
$

Then you can use %?pete and %?ralph to refer to each of them, although actually %?pe and %?ra are sufficient to disambiguate.

Table 8-1 lists all of the ways to refer to background jobs. We have found that, given how infrequently people use job control commands, job numbers or command names are sufficient, and the other ways are superfluous.

Table 8-1. Ways to refer to background jobs

Reference Background job
N Process ID N
-N Process group ID N
%N Job number N
%string Job whose command begins with string
%?string Job whose command contains string
%+, %% Most recently invoked background job
%- Second most recently invoked background job

8.2.2. Suspending a Job

Just as you can put background jobs into the foreground with fg, you can also put a foreground job into the background. This involves suspending the job, so that the shell regains control of your terminal.

To suspend a job, type CTRL-Z[114] while it is running. This is analogous to typing CTRL-C (or whatever your interrupt key is), except that you can resume the job after you have stopped it. When you type CTRL-Z, the shell responds with a message like this:

[114] This assumes that the CTRL-Z key is set up as your suspend key; just as with CTRL-C and interrupts, this is conventional but by no means required.

[1] + Stopped                   command

Then it gives you your prompt back. It also puts the suspended job at the top of the job list, as indicated by the + sign.

To resume a suspended job so that it continues to run in the foreground, just type fg. If, for some reason, you put other jobs in the background after you typed CTRL-Z, use fg with a job name or number. For example:

fred is running ...
CTRL-Z
[1] + Stopped                   fred
$ bob &
[2]     bob &
$ fg %fred
fred resumes in the foreground ...

The ability to suspend jobs and resume them in the foreground comes in very handy when you only have a single connection to your system,[115] and you are using a text editor like vi on a file that needs to be processed. For example, if you are editing an HTML file for your web server, you can do the following:

[115] Such as when you're dialed in from home to your office, or connected to a remote system over the Internet via telnet or ssh.

$ vi myfile.html
Edit the file ...  CTRL-Z
[1] + Stopped                  vi myfile.html
$ lynx myfile.html       Preview results with a text-only browser
You see that you made a mistake
$ fg
vi comes back up in the same place in your file

Programmers often use the same technique when debugging source code.

You will probably also find it useful to suspend a job and resume it in the background instead of the foreground. You may start a command in the foreground (i.e., normally) and find that it takes much longer than you expected -- for example, a grep, sort, or database query. You need the command to finish, but you would also like control of your terminal back so that you can do other work. If you type CTRL-Z followed by bg, you move the job to the background.[116]

[116] Be warned, however, that not all commands are "well-behaved" when you do this. Be especially careful with commands that run over a network on a remote machine; you may end up "confusing" the remote program.

8.2.3. Disowning a Job

Normally, when you log out, the shell sends the HUP signal (see the next section) to any background jobs. If you've started a long-running job in the background and want it to complete no matter what, you should indicate this to the shell using the disown command with one or more job ID numbers as arguments. With no arguments, all background jobs are disowned.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.