It can be costly for the parent process to wait while a child process completes its work, particularly if the parent is already done.
Shell processes often progress in a sequence of programs, one working with the output of the proceeding one. Some of these programs started as monolithic Shell scripts that were broken into multiple scripts for maintainability. If there is a large volume of serial data, it makes sense to use PipesAndFilters
. In other cases, the environment of the first scripts provides input for later scripts. Since earlier scripts defer to later scripts to finish the work, they do no work and produce no output after starting their successor scripts. These scripts form a structure of FORTRAN chaining, or tail recursion. As with tail recursion, each step in the chain remains until its child process terminates--by default, Shells wait(2)
for the deaths of all their children. This creates an unnecessarily large number of processes. Yet to fold the code of the child process back into the parent process would re-introduce the monolithic structure.
Take a cue from FORTRAN chaining, and reuse the same process every time, just as chaining re-uses the same memory. You can do this using exec. So for some script specialJoin:
cat $DATABASE | (
while expr $NRECORDS \> 0; do
. . . .
instead of writing:
do this in the first script instead:
Note that this is a form of TailCallOptimization