< Day Day Up > |
8.6. SubshellsTo conclude this chapter, we will look at a simple 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:
Just as important are the things that a subshell does not inherit from its parent:
We covered some of this 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 command 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 the last chapter, with a subshell instead of a command block: ( while read line; do echo "$(alg2rpn $line)" done ) | dc The code inside the parentheses will run as a separate process. This is usually less efficient than a command block. The differences in functionality between subshells and command 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 command block are known to the shell code after the block, whereas those defined in a subshell are not. For example, consider this code: { hatter=mad trap "echo 'You hit CTRL-C!'" INT } while true; do echo "\$hatter is $hatter" sleep 60 done If you run this code, you will see the message $hatter is mad every 60 seconds, and if you hit CTRL-C, you will see the message, You hit CTRL-C!. You will need to hit CTRL-Z to stop it (don't forget to kill it with kill %+). Now let's change it to a nested subshell: ( hatter=mad trap "echo 'You hit CTRL-C!'" INT ) while true; do echo "\$hatter is $hatter" sleep 60 done If you run this, you will see the message $hatter is; the outer shell doesn't know about the subshell's definition of hatter 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 command blocks over the scope of variables and signal traps. Therefore, we feel that you should use subshells instead of command blocks if they are to contain variable definitions or signal traps—unless efficiency is a concern. |
< Day Day Up > |