8.6 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 subshell 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 subshells in more detail. 8.6.1 Subshell InheritanceThe most important things you need to know about subshells are what characteristics they get, or inherit , from their parents. These are as follows:
The first three of these are inherited by all subprocesses, while the last is unique to subshells. Just as important are the things that a subshell 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 Nested SubshellsSubshells need not be in separate scripts; you can also start a subshell 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 brackets), and that code will run in a subshell. We'll call this a nested 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 will run as a separate process. 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 nested subshell obeys the above rules of subshell 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 nested 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 will terminate. If a language supports code nesting, then it's considered desirable that definitions inside a nested unit have a scope limited to that nested unit. In other words, nested 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.
|
|