In This chapter:
Job States
Obtaining Job Information
Changing a Job’s State
Other Applications of Job Control
Job Control and Window Systems
Each command you issue starts what the shell calls a job. The shell keeps track of all jobs that have not terminated and provides facilities to manipulate those jobs. As a result, you have a lot of control over the execution of your commands. Job control has many uses:
You can stop a job to suspend it, then resume the job at a later time. If you are composing a mail message and find that you need to check some files before proceeding, you can suspend the mailer, run a bunch of commands, and then resume the mailer where you left off. If you are using gopher and you see an announcement about an interesting mailing list, you don’t have to quit gopher to sign up; instead, you can suspend gopher, send a mail message to join the list, and then resume gopher where you left off.
Some programs provide an escape mechanism for passing single commands to a subshell for execution. Job control provides a more convenient alternative when you want to run several commands in a row. It’s easier to stop the editor and restart it later than to type the escape prefix multiple times. The former method is faster because you are not starting up a separate subshell to handle each command. Additionally, you get to use filename completion and the history of your login shell, facilities which are unavailable to commands that run as shell escapes.
You can move a job between the foreground and the background. For example, if a command takes longer than you expected, you can put it into the background and do other things while it runs. Or, you can background an ftp job after beginning a file transfer, work on something else in the meantime, and then return the job to the foreground when the transfer is done.
You can kill a job, e.g., if you are trying to rlogin to a machine which takes so long to respond that you tire of waiting.
You can force background jobs to stop when they try to write to your terminal, and then bring them to the foreground when you want to see their output. In this manner, you can keep the output of separate commands from getting intermixed on the screen.
This chapter discusses job states, how to obtain information about your current jobs, and how to manage job execution so that you can switch from one job to another.
You start a job by issuing a command. A job can be in one of three states: foreground, background, or stopped (suspended).[27] Normally, a command runs as a foreground job:
% grep include *.[ch]
Run a job in the foreground
If you end a command line with &
, the shell starts a background job and prints the job number and process ID:
% tar xf archive.tar &
Run a job in the background
[1] 27163 Shell reports the job number and process ID
If you type CTRL–Z
[28] while a foreground job is running, the job ceases executing and becomes suspended:
% sort mydata > mydata2
Start a foreground job
CTRL-Z Suspend it
Stopped Shell reports that the job has been stopped
Only one foreground job can exist at a time, but you can have multiple jobs stopped or running in the background.
If you find that you cannot stop jobs, you can consider two courses of action. First, ensure that you have the susp
character defined:
% stty susp ^z
Second, some systems require that you explicitly specify the "new” terminal driver if job control is to work:
% stty new
Try the commands shown above from the command line. If either enables job control, add it to your ˜/.login file. Otherwise, it may be that your system simply doesn’t support job control. Consult with your system administrator.
The jobs command reports any jobs that you have running in the background and any jobs that are stopped. Figure 15-1 shows a job list that might result during a session of analyzing a set of data files.
If a job consists of a multiple-command pipeline, commands in the pipeline that have finished are displayed on a different line than those that are still running. The third job in Figure 15-1 demonstrates this type of display: grep and cut have finished executing, but anova is still running.
jobs –l displays jobs in long format. The long format reports the process ID along with the usual information.
In tcsh, you can cause automatic jobs execution whenever you stop a job, if you set the listjobs shell variable in your ˜/.cshrc file as follows:
set listjobs
If you would rather have jobs –l executed instead, set listjobs to long, as shown below:
set listjobs = long
By default, when a job finishes (or otherwise changes state), the shell informs you that the job has completed only when it must print another prompt.[29] If you want to be notified immediately, set the notify shell variable in your ˜/.cshrc file as shown below:
set notify
set notify provides you with quicker notification. However, if a notification message occurs in the middle of the output from another command, you might miss it in the jumble. You may not find that a problem, since you can always use jobs to find out if a job is still running. Try notification both ways and see which one you prefer.
jobs output indicates two special jobs: current and previous jobs. These jobs are flagged with a +
and –
next to the status column (see the fourth and first jobs in Figure 15-1). When a job is stopped (or put into the background, when there are no stopped jobs), it becomes the current job. Any job that was current at the time becomes the previous job. When the current job terminates, the previous job once again becomes the current job.
A job can be moved from one state (foreground, background, or suspended) to any other state. The commands used to manipulate jobs are listed in Table 15-1; %
j
designates the job on which you wish to operate. fg, bg, kill, and stop can take multiple job specifier arguments, each of which is processed in turn. Table 15-2 shows the various forms that %
j
can take.
Command | Effect of Command |
| Stop the foreground job |
| Interrupt (terminate) foreground job |
| Bring stopped or background job to foreground |
| Move stopped job to background |
| Kill (terminate) stopped or background job |
| Stop background job |
| Suspend current shell (if non-login shell) |
| Display current job list |
Specifier | Job to Which the Specifier Refers |
| Current job ( |
| Previous job |
| Job number |
| Job whose command line begins with |
| Job whose command line contains |
You can often refer to a job more easily by name than by number, although %
str
and %?
str
are ambiguous if they match more than one job in your job list. When such a situation occurs, the shell provides warning. For example, our job list includes two jobs beginning with vi and two jobs containing reference.ms. As a result, the following commands are ambiguous:
%fg %vi
%vi: Ambiguous. %fg %?ref
%?ref: Ambiguous.
If you use %?
str
to refer to a job and the shell responds with No match
, the shell is interpreting the ?
as a pattern-matching character. If that happens, try escaping the ?
with a backslash, i.e., use %?
str
. Some versions of the shell require the backslash for fg, bg, kill, and stop. Others require it only for kill and stop.
The job control commands that you use to manage jobs by moving them from one state to another are discussed in the following sections, and are summarized in Figure 15-2.
CTRL–Z
stops the current foreground job. Some programs ignore CTRL–Z
part of the time, e.g., vi cannot be stopped if you are in insert mode.
To stop a background job, use stop. For example, any of the following commands will stop the grep/cut/anova pipeline shown in Figure 15-1:
%stop %3
%stop %gr
%stop %?ano
You can also stop a background job by bringing it to the foreground (see Resuming a Job below), and then typing CTRL–Z
.
Stopping a stopped job has no effect, as shown below:
% stop %1
%1: Already stopped
Beware of inadvertently starting two editing sessions on the same file. Multiple editing sessions can occur if you stop an editor and then issue a new editor command for the file, instead of resuming the editor job that you had stopped. If you switch between sessions, you can have problems because each editing job may wipe out the changes you saved in the other.
fg brings a stopped or background job to the foreground:
%fg %4
Resume the second vi command %fg %pr
Move print job from background to foreground
bg restarts a stopped job in the background. If you start a command and decide that it’s taking too long, you can stop it with CTRL–Z
, and then use bg to move it to the background. At that point, you can continue working on other things.
If a background job tries to read from the terminal, it stops. Bring the job to the foreground to interact with it.
The fg and bg commands have some shorthand forms:
If fg and bg are issued without a job specifier, they default to the current job.
If you type in a job specifier by itself, the fg command is assumed.
If you add a &
to a specifier, bg is assumed instead of fg.
These rules are illustrated in Table 15-3.
A job can be terminated if it is stopped, or running in the foreground, or running in the background. Your interrupt character (typically CTRL–C
) usually terminates the current foreground job. If a job is stopped or running in the background, use the kill command. For example, to kill job 5, do the following:
% kill %5
[5] Terminated pr Results2 | lpr
Alter natively, bring the job to the foreground, and then type CTRL–C
.
Jobs retain their assigned number. For example, if you kill job 1, jobs 2 and up are not renumbered.
Some jobs catch CTRL–C
, and therefore cannot be killed by it. When this condition occurs, try stopping the job with CTRL–Z
, then issue a kill command. Occasionally, even kill does not kill a job (some programs catch the signal that kill sends). In such cases, you can use kill –9 to send an uncatchable signal.
The suspend job control command works only in subshells (non-login shells). It suspends the subshell and returns you to the parent shell. You can resume the subshell like any other job using fg.
suspend is especially useful for subshells that were started with su, because you need to type the password only when you start the subshell. Thereafter, you can simply move into and out of the subshell. suspend is even more convenient if you have one of those annoying versions of su that does not read the ˜/.cshrc file of the account to which you are switching. In such cases the su forces you to source it explicitly when you start the subshell. With suspend, you need to source the file only once.
To make suspend easier to use, put the following alias in the ˜/.cshrc of the account you’re switching to:
alias z suspend
This section describes other ways in which job control is useful.
Putting a command in the background is handy when you want to do other things while the job is running, but the command may write output to the terminal at inconvenient times. If you are editing a file or composing a mail message, you may not want a background job to splatter output all over the screen. Or, if you have multiple background jobs, their output streams may interfere with each other. To avoid these problems, you can use the following command to force background jobs to stop when they are ready to write to the terminal:
% stty tostop
When you’re ready to see the output of a background job that is stopped waiting to write, bring the job to the foreground.
To let background jobs write to the terminal at any time, use the following command:
% stty -tostop
The following command sequence illustrates the difference between stty tostop and stty –tostop:
%stty tostop
Turn tostop on %date &
Run command in the background [1] 24980 Shell reports the job number and the process ID [1] + Suspended (tty output) date Job stops when ready to produce output %fg
Bring the job to the foreground date Shell echoes command line Mon Sep 12 11:59:14 CDT 1994 Job writes output %stty -tostop
Turn tostop off %date &
Run the command in the background [1] 24982 Shell prints the job number and the process ID Mon Sep 12 11:59:21 CDT 1994 Job writes output without stopping [1] Done date Shell notifies you that the job has finished
To specify the kind of output behavior that you want for background jobs, put the appropriate stty command in your ˜/.login file.
Interactive commands usually expect to read from and write to your terminal. Some interactive commands like more and vi are not useful in the background because they immediately try to read from the terminal and stop. But others can be put in the background during a long operation that doesn’t require your attention. For example, if you are using anonymous FTP to perform a file transfer, the sequence of FTP commands might look something like the following:
%ftp
some.machine.name
User:anonymous
Password:(type your e-mail address here)
ftp>cd pub
ftp>mode binary
ftp>get software.tar.Z
ftp>bye
If the get
operation is slow, you may want to do other work in the meantime. Do so by running ftp interactively up through the get
command, then stop the job and move it to the background:
%ftp
some.machine.name
User:anonymous
Password:(type your e-mail address here)
ftp>cd pub
ftp>mode binary
ftp>get software.tar.Z
CTRL-Z Stopped. %bg
[1] ftpsome.machine.name
&
Putting ftp in the background allows the transfer to proceed while you work on other things. After the transfer finishes, ftp tries to read the terminal to solicit another command from you and stops. The shell then tells you that ftp is waiting for you to continue typing:
[1] + Stopped (tty input) ftp some.machine.name
Return the job to the foreground to resume your ftp session:
% fg
Bring ftp to the foreground
You should be aware of the following subtlety when you background an interactive command: the command may have already printed its next prompt by the time you resume it, and might not be smart enough to reprint the prompt again. Just go ahead and type the next input line.
When you have so many background jobs that the system slows down unacceptably, you should probably stop some of the jobs. Suppose that you start a lot of big sort jobs in the background:
%sort datal -o datal &
[1] 8273 %sort data2 -o data2 &
[2] 8274 . . . %sort data10 -o data10 &
[10] 8282
Shortly thereafter, your system administrator reports that everybody is complaining about how slowly the machine is running, and notes that you are the culprit. You can alleviate the situation by stopping several of the jobs:
% stop %2 %3 %4 %5 %6 %7 %8 %9 %10
After the first job finishes, start the second job running in the background again:
% %2 &
When the second job finishes, restart the third job, etc. Alternatively, you can restart the jobs in sequence, as shown below:
% %2 ; %3 ; %4 ; %5 ; %6 ; %7 ; %8 ; %9 ; %10
If you are using a system that allows you to open multiple terminal windows, you can switch between windows as an alternate form of job control (e.g., if a command is slow in one window, you can switch to another window). However, even if you have access to multiple windows, there are still reasons to use job control:
Commands manipulated by job control are often related; therefore, using your history in constructing those commands can be useful. In a windowing system, the history of one window is not directly usable in another.
Establishing new windows can be more cumbersome and slower than switching between jobs in a single window.
Starting lots of windows means that you have more of them to keep track of, move around, iconize, etc. Job control helps keep the display more manageable by reducing clutter.
I find it more convenient to use multiple windows if I need to switch between jobs, and if each job requires a full-screen display. Otherwise, I generally find that using job control to switch between jobs in a single window is easier.
[27] The terms “stopped” and "suspended” are interchangeable; both signify a non-running job.
[28] Or whatever your susp
character is. If you don’t know what it is, see Chapter 5, Setting Up Your Terminal.
[29] Thus, if you start a command in the background and then just wait for the shell to tell you when the job is done, it never will. You need at least to hit RETURN
every now and then to get a new prompt.