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

Completed solutions should probably go in LinuxHints/UsefulOneLiners.

Keeping while in context

From BobDunlop

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.

LinuxHints/BashTricks (last edited 2010-09-03 08:21:41 by 148)