Chapter 15. Job Control

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.

Job States

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.

Obtaining Job Information

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.

Sample output from jobs command
Figure 15-1. Sample output from jobs command

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

Finding Out When Jobs Finish

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.

The Current and Previous Jobs

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.

Changing a Job’s State

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.

Table 15-1. Job Control Commands

Command

Effect of Command

CTRL–Z

Stop the foreground job

CTRL–C

Interrupt (terminate) foreground job

fg %j

Bring stopped or background job to foreground

bg %j

Move stopped job to background

kill %j

Kill (terminate) stopped or background job

stop %j

Stop background job

suspend

Suspend current shell (if non-login shell)

jobs

Display current job list

Table 15-2. Job Specifiers

Specifier

Job to Which the Specifier Refers

%

Current job (%+ and %% are synonyms for %)

%–

Previous job

%n

Job number n

%str

Job whose command line begins with str

%?str

Job whose command line contains str

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.

Stopping a Job

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
Commands that move jobs from one state to another
Figure 15-2. Commands that move jobs from one state to another

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.

Resuming a Job

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.

Shorthand forms of fg and bg

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.

Table 15-3. Alternate Forms of the fg and bg Commands

fg Command

Synonym(s)

bg Command

Synonym(s)

fg %

fg or %

bg %

bg or %&

fg %3

%3

bg %3

%3&

fg %pr

%pr

bg %pr

%pr&

fg %?ano

%?ano

bg %?ano

%?ano&

Killing a Job

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.

Killing stubborn Jobs

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.

Suspending a Non-Login Shell

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

Other Applications of Job Control

This section describes other ways in which job control is useful.

Controlling Background Job Output

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.

Backgrounding Interactive Jobs

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]  ftp some.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.

Using Job Control To Improve System Response

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

Job Control and Window Systems

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset