In the simplest form of interprogram cooperation enabled by
inexpensive process spawning, a program runs another to accomplish a
specialized task. Because the called program is often specified as a
Unix shell command through the
system(3)
call, this is often called
shelling out
to the
called program. The called program inherits the user's keyboard and
display and runs to completion. When it exits, the calling program
resumes control of the keyboard and display and resumes
execution.[68] Because the calling program does not
communicate with the called program during the callee's execution,
protocol design is not an issue in this kind of cooperation,
except in the trivial sense that the caller may pass command-line
arguments to the callee to change its behavior.
The classic Unix case of shelling out is calling an editor from
within a mail or news program. In the Unix tradition one does
not
bundle purpose-built editors into programs
that require general text-edited input. Instead, one allows the user
to specify an editor of his or her choice to be called when editing
needs to be done.
The specialist program usually communicates with its parent through the
file system, by reading or modifying file(s) with specified
location(s); this is how editor or mailer shellouts work.
In a common variant of this pattern, the specialist program may
accept input on its standard input, and be called with the
C library entry
point popen(..., "w") or as part of a
shellscript. Or it may send output to its standard output, and be
called with popen(..., "r") or as part of a
shellscript. (If it both reads from standard input and writes to
standard output, it does so in a batch mode, completing all reads
before doing any writes.) This kind of child process is not usually
referred to as a shellout; there is no standard jargon for it, but it
might well be called a ‘bolt-on’.
They key point about all these cases is that the specialist
programs don't handshake with the parent while they are running. They
have an associated protocol only in the trivial sense that whichever
program (master or slave) is accepting input from the other has to be
able to parse it.
The mutt
mail user agent is the modern
representative of the most important design tradition in Unix email
programs. It has a simple screen-oriented interface with
single-keystroke commands for browsing and reading mail.
When you use
mutt
as a mail composer (either by calling it
with an address as a command-line argument or by using one of the
reply commands), it examines the process environment variable
EDITOR, and then generates a temporary file name. The
value of the EDITOR variable is called as a command
with the tempfile name as an argument.[69] When that command terminates,
mutt resumes on the assumption that the
temporary file contains the desired mail text.
Almost all Unix mail- and netnews-composition programs observe
the same convention. Because they do, composer implementers don't
need to write a hundred inevitably diverging editors, and users
don't need to learn a hundred divergent interfaces. Instead, users
can carry their chosen editors with them.
An important variant of this strategy shells out to a small proxy
program that passes the specialist job to an already-running instance
of a big program, like an editor or a Web browser. Thus, developers
who normally have an instance of emacs
running on their X display can set
EDITOR=emacsclient, and have a buffer pop open in
their emacs when they request editing in
mutt. The point of this is not really to
save memory or other resources, it's to enable the user to unify all
editing in a single emacs process (so that,
for example, cut and paste among buffers can carry along internal
emacs state information like font
highlighting).