Job control
A job is a collection of processes grouped together and
identified by a small integer. In the example above, the job number
for process 16403 was 1 . When a UNIX
command is sent to the background using & , a
single job is created consisting of one or more processes. That job
will initially be sent to the background, but can be moved into the
foreground or destroyed in much the same way as an individual
process. Consider the following pipe:
$ cat testfile | wc &
[2] 2374
A single job (number 2 ) has been created in the
background, but two processes are required, one for
cat and one for wc . The process number
2374 is that of the last command in the pipe, namely
wc . You can destroy the job, and consequently both
processes, with
$ kill -s KILL %2
(instead of giving the command kill the number of
the process to send a signal to, we give it the number of the job
preceded by a percent character).
Worked example
Arrange to be given an 'alarm call' after 2 minutes.
Solution: Create a script that uses
sleep to cause it to suspend for 120 seconds, and then
use echo to write a message to your screen. The script
should be run in the background.
$ cat >myalarm
sleep 120
echo Your alarm call ...
ctrl-D
$ sh myalarm &
If you now typed ps , you would find (amongst
others) two processes:
23624 p2 S 0:00 sh myalarm
23625 p2 S 0:00 sleep 120
indicating that both the script myalarm and the command
sleep had been invoked. You could,, of course, have
used vi to create myalarm .
You may have several jobs running at any one time, and command
jobs will list them. For example,
$ jobs
[1] Stopped testA
[2]- Running sh myalarm &
[3]+ Running testB &
indicates that you have 3 jobs. Jobs 2 and 3 are running in the
background, whereas number 1 has been stopped.
Note that the word Suspended is used on some systems instead of
Stopped . This means that the system is not running
that job at all; it is suspended pending reactivation. You can try
creating a few jobs yourself - the script myalarm from
the last worked example is suitable to experiment with. Take a copy
of myalarm , call it (say) newalarm , and
execute both in the background; you should get a dialogue similar
to:
$ cp myalarm newalarm
$ sh myalarm &
[1] 25816
$ sh newalarm &
[2] 25820
$ jobs
[1]- Running sh myalarm &
[2]+ Running sh newalarm &
If you have jobs running or stopped, one of them will be the
default job, and is indicated in the output from
jobs by the symbol + after its number -
in the above example this would be job 3. The default job is the
job that was most recently created (or sent a signal by you). If
you have two or more running, one will be indicated by a
- symbol, which indicates that if the default job was
to terminate, this one would then become the default. In the
example above this would be job 2. The default job is also known as
%% .
Any job that is in the background or is stopped can become the
foreground job simply by giving the job number (preceded by
% ) as argument to the command fg
('foreground'). Similarly, any stopped job can be reactivated to
run in the background by the command bg
('background'):
$ bg %1
[1]+ testA &
$ jobs
[1] Running testA
[2]- Running sleep 120 &
[3]+ Running testB &
$ fg %%
The reason for having default jobs is that quite often, when you
have sent a job into the background, you will either want it to be
brought back to the foreground or perhaps kill ed. In
practice, you tend to find that you have not created any new jobs
in the meantime, and it is useful to have a shorthand for referring
to the default job.
Any job sent to the background will still have its standard
output and standard error streams set up as if the job were still
in the foreground. What this means for the user is that if a
background job wants to write to your terminal, it will do so (so
you should not be surprised if, when running jobs in the
background, messages do appear on your screen). Yet any input you
type on your terminal will be sent to the current foreground
process or to the shell - if you had many background processes
running, the system couldn't be expected to decide which job your
input was intended for, so can only send it to a foreground
process.
A background job must therefore do something sensible if it
requires input from the terminal. What happens in this case is that
the background job automatically stops - a signal called
SIGTTIN is sent to it when it attempts to read from
the terminal, and this signal has the effect of stopping the job.
Consider:
$ cat &
[1] 13249
$
[1]+ Stopped (SIGTTIN) cat
The command cat , in the absence of any arguments,
reads from standard input; cat is run in the
background, so immediately demands input, but since it is in the
background it cannot receive it. It therefore becomes suspended and
you are sent a message to tell you of this fact.
If you send a job to the background that requires input from
your terminal, it will become stopped as soon as it requires that
input, and you must bring it to the foreground if you wish it to
complete executing. Try this with mailx :
$ mailx -s "Test" chris &
[1] 24545
[1]+ Stopped (SIGTTIN) mailx
$ fg %1
(you can type in your message now)
|