This chapter describes Unix's facilities for running more than one command
at once.
With the X Window System, the simplest way of running another command
is to start a new
xterm
and do it there.
This makes these facilities less useful than they were
back in the days when Unix was used via a simple VDU.
However, X and Unix only work so well together because Unix was designed to
run more than one simultaneous command per user.
Also, some of the
vi
editor's most powerful features depend on this.
The execution of a command is known as a process. All multi-user operating systems have to run more than one process at once but Unix was the first to let each user have more than one process. We call this: user multi-processing. In fact, we have already seen Unix running more than process; that's what happens when we execute a pipeline. Something remarkable about this:
$ ls | tee tout | wc -l
$
is that Unix automatically synchronises the execution of the three processes so that each stage only produces output when the next is ready to consume it.
Being able to multi-process can save us much waiting. Suppose we wish to sort a huge file, we might type this:
$ sort -o gigantic gigantic
<----- a long delay
$
We would have to wait while
sort
finished before we could give our next command.
If we add an ampersand
(&
) to the end of the command, Unix does not wait for the
sort
process to finish before it gives us a prompt:
$ sort -o gigantic gigantic &
26970
$
The number is the unique process identity (PID) of the new process. If we don't dawdle, we can see what processes we have running:
$ ps
PID TTY TIME CMD
26970 pts/45 0:01 sort
26914 pts/45 0:00 sh
$
Surprisingly,
ps
does not show itself.
It does however, show
sort
and the shell.
(The
sh
is Unix's
name for the Bourne shell.)
Later,
ps
shows that the sorting is over:
$ ps
PID TTY TIME CMD
26914 pts/45 0:00 sh
$
TTY
indicates the input/output connection between the
xterm
and Unix.
No
xterm
process appears in the list
because, by default,
ps
only shows processes associated with a terminal.
The PID can be used to stop a process:
$ kill 26970 $ kill -9 26970 $
The second form of the command gets rid of stubborn processes.
Commands such as
xman
and
xedit
start a new window.
If we issue the command without an ampersand,
we can't use the old window until the new one disappears.
That is why we should use this form of command:
$ xman & 26991 $ xedit file & 26993 $
for programs that run in their own windows.
Unix has several commands for running other commands later,
at
is one of them:
$ at -m 0730 tomorrow sort -o gigantic gigantic ^D $
Notice how the command
at
will execute is read from standard input.
When an
xterm
stops, the processes it started are stopped automatically.
The following command lets users leave processes running after the
xterm
stops:
$ nohup xman &
26997
$ Sending output to nohup.out
Processes can even be left running after we log off:
$ nohup sort -o gigantic gigantic &
27001
$ Sending output to nohup.out
Unfortunately
nohup
's output obscures shell's prompt.
This next section is very complicated; we tackle it now because it will help us to understand Unix's means of executing shell scripts when we cover them in Chapter ??.
Unix lets us start extra shells in the same window. Now that we know the name of the Bourne shell, we can easily do so. To clarify what follows, we will make a set of directories to play with:
$ mkdir level1 level1/level2 level1/level2/level3
$
We then start a new shell process and change to another directory:
$ sh $ cd level1 $
We do that twice more and display our current directory and list of processes:
$ sh $ cd level2 $ sh $ cd level3 $ pwd /homedir/cms/ps/book.unix/level1/level2/level3 $ ps PID TTY TIME CMD 26914 pts/45 0:00 sh 27009 pts/45 0:00 sh 27010 pts/45 0:00 sh 27015 pts/45 0:00 sh $
Process
26914
is the original shell in the original directory and is waiting for
process
27009
to finish.
Process
27009
is in
level1
waiting for
27010
which is in
level2
waiting for
27015
.
Process
27015
is the last shell that prompted us; it is in
level3
.
If we now stop the three extra processes we will be back where we started. On the way we can confirm that the waiting shells were in the predicted directories:
$ ^D $ pwd /homedir/cms/ps/book.unix/level1/level2 $ ^D $ pwd /homedir/cms/ps/book.unix/level1 $ ^D $ pwd /homedir/cms/ps/book.unix $ ps PID TTY TIME CMD 26914 pts/45 0:00 sh $
When we were in
level3
, we had a stack of four shell processes running.
Programmers will realise the importance of this: it is the mechanism that allows local variables and recursion in shell scripts. It also explains why shell scripts cannot easily leave the user in another directory!
The power of processes makes it possible for the user of interactive
commands, such as mailers and editors, to escape from them temporarily
to execute other commands.
For example if we were using the
vi
editor, we could execute the
date
command like this:
...(vi)
:!date
Thu Mar 20 14:50:23 GMT 1997
[Hit return to continue]
(vi)...
It is
vi
that asks us to hit the return key after the execution of
date
.
Of course, we can run any command - even the shell:
...(vi) :!sh $ cp file1 file1.bu $ cp file2 file2.bu $ cp file3 file3.bu $ ^D [Hit return to continue] (vi) ...
Running the shell means we can do lots of commands before returning to the editor.
An even more powerful facility is that
vi
can take text from the screen, feed it through any Unix command
and replace the text on the screen with the output from the command.
Here we sort all the lines in the file without leaving
vi
:
...(vi)
:1,$!sort
(vi)...
Here we format all the text being edited:
...(vi)
:1,$!fmt
(vi)...
We could easily use this facility to put a C program through a pretty-printer.
We can even execute Unix commands that we are editing:
...(vi)
:1,$!sh
(vi)...
without leaving the window!
None of these powerful facilities would be possible without Unix's user multi-processing.
pending
pending
pending
pending