8.6. Shell Subprocesses and SubshellsCoroutines clearly represent the most complex relationship between processes that the Korn shell defines. To conclude this chapter, we will look at a much simpler type of interprocess relationship: that of a shell subprocess with its parent shell. We saw in Chapter 3 that whenever you run a shell script, you actually invoke another copy of the shell that is a subprocess of the main, or parent, shell process. Now let's look at them in more detail. 8.6.1. Shell Subprocess InheritanceThe most important things you need to know about shell subprocesses are what characteristics they get, or inherit, from their parents. These are as follows:
The first three characteristics are inherited by all subprocesses, while the last two are unique to shell subprocesses. Just as important are the things that a shell subprocess does not inherit from its parent:
We covered some of this earlier (in Chapter 3), but these points are common sources of confusion, so they bear repeating. 8.6.2. SubshellsA special kind of shell subprocess is the subshell. The subshell is started within the same script (or function) as the parent. You do this in a manner very similar to the code blocks we saw in the last chapter. Just surround some shell code with parentheses (instead of curly braces), and that code runs in a subshell. For example, here is the calculator program, from above, with a subshell instead of a code block:
( while read line'?adc> '; do print "$(alg2rpn $line)" done ) | dc The code inside the parentheses runs as a separate process.[125] This is usually less efficient than a code block. The differences in functionality between subshells and code blocks are very few; they primarily pertain to issues of scope, i.e., the domains in which definitions of things like shell variables and signal traps are known. First, code inside a subshell obeys the above rules of shell subprocess inheritance, except that it knows about variables defined in the surrounding shell; in contrast, think of blocks as code units that inherit everything from the outer shell. Second, variables and traps defined inside a code block are known to the shell code after the block, whereas those defined in a subshell are not.
For example, consider this code:
{ fred=bob trap 'print "You hit CTRL-C!"' INT } while true; do print "\$fred is $fred" sleep 60 done If you run this code, you will see the message $fred is bob every 60 seconds, and if you type CTRL-C, you will see the message, You hit CTRL-C!. You will need to type CTRL-\ to stop it (don't forget to remove the core file). Now let's change it to a subshell:
( fred=bob trap 'print "You hit CTRL-C!"' INT ) while true; do print "\$fred is $fred" sleep 60 done If you run this, you will see the message $fred is; the outer shell doesn't know about the subshell's definition of fred and therefore thinks it's null. Furthermore, the outer shell doesn't know about the subshell's trap of the INT signal, so if you hit CTRL-C, the script terminates. If a language supports code nesting, definitions inside a nested unit should have a scope limited to that nested unit. In other words, subshells give you better control than code blocks over the scope of variables and signal traps. Therefore we feel that you should use subshells instead of code blocks if they are to contain variable definitions or signal traps -- unless efficiency is a concern. This has been a long chapter, and it has covered a lot of territory. Here are some exercises that should help you make sure you have a firm grasp on the material. The last exercise is especially difficult for those without backgrounds in compilers, parsing theory, or formal language theory.
Copyright © 2003 O'Reilly & Associates. All rights reserved. |
|