Archive

Bash Tricks

This page is for Bash programming tips and tricks, most of which will only be code fragments.

Completed solutions should probably go in Useful One-Liners.

Keeping while in context

From Bob Dunlop

I’ve long been annoyed by the behaviour of Bash and pipelines as exhibited by the following small script.

#!/bin/bash          
generate() {
    echo "one"
    echo "two"
    echo "three"
}         
last="dummy"          
generate | while read x     
do         
    last=$x   
    echo "x= $x last= $last"
done     
echo "last= $last"

Which produces the following output.

x= one last= one     
x= two last= two     
x= three last= three     
last= dummy

Notice that despite “last” being updated within the while loop this change is not reflected in the main body of the code. The reason being that the while statement as part of a pipeline is being run in a separate subshell.

Since I frequently need to process generated output and set flags accordingly I find this behavior rather inconvenient.

The following is a recoding of the while loop which avoids the pipeline (replacing it with a named pipe) that allows the while to be run by the current shell.

while read x
do     
    last=$x     
    echo "x= $x last= $last"     
done < <( generate )

Which produces the better (for me at least) output:

x= one last= one     
x= two last= two     
x= three last= three     
last= three

Warning the  <( command ) construct is specific to bash, and ZSH. The space between the two  < in the example is also important and required.

Leave a Reply