A command or list of commands can be executed in a new shell called a subshell, whose parent is the current shell. Subshells take the environment of their parent. I/O redirection can occur between the child and parent shells, but the subshell can never modify the parent environment. This is desirable when you want to change the shell environment for the execution of those commands, such as by setting variables, but you do not want to change the environment that the script itself is running in. It's also desirable to run subshells when you want to have multiple, long-running processes started and running in the background at the same time. A shell can spawn multiple subshells, and subshells, in turn, can recursively spawn any number of their own subshells. Figure 1 illustrates the process.
Figure 1. How a subshell interacts with its parent shell
The shell sometimes automatically spawns subshells of its own, such as when built-ins are used on a pipeline. When in a subshell, the shell
$ parameter expands to the process ID (PID) of the parent shell, never of the subshell.
To run a group of commands in a subshell, enclose them in parentheses. You can use redirection to send input to the subshell's standard input or to send its collective output to a file or a pipeline.
Try typing what's shown in Listing 17 in your home directory. It creates an example directory and some test files, provided that you don't already have a directory named example.
Listing 17. Making a group of files in a subshell
$ pwd /home/user $ (mkdir example; cd example; touch A B C) $ pwd /home/user $ cd example; ls A B C $ pwd /home/user/example $
In this example, the shell spawns a subshell that runs in the background, making the example directory and using
touch to create three dummy files in that directory. Meanwhile, the shell returns to
the prompt in your home directory.
Subshells are convenient both at the command line and in scripts when you have a group of commands that take a long time to execute. To keep your shell free, you can run it in the background, or run many of them in the background:
( group-of-long-running-commands ) & ( another-group-of-long-running-commands ) & ( yet-another-group-of-long-running-commands ) &
It's important to understand how variables work with subshells. Since the subshell environment is a duplicate of its parent, it inherits all of the variables of the parent. But the parent shell never sees any changes that are made in the subshell environment, and the subshell, in turn, never sees any changes that are made in the parent after the subshell is spawned.
Listing 18. Shell script demonstrating variable behavior in subshells
#!/bin/sh # Demonstrates variable behavior in a subshell environment VAR=10 echo "VAR is" $VAR ( echo "In the subshell, VAR is still" $VAR VAR=$(($VAR+5)) echo "The new value of VAR in the subshell is" $VAR ) echo "Outside of the subshell, VAR is" $VAR
Now try executing the script by typing its name, as shown in Listing 19.
Listing 19. Output of the vartest script
$ vartest VAR is 10 In the subshell, VAR is still 10 The new value of VAR in the subshell is 15 Outside of the subshell, VAR is 10 $