Question

This is a followup to bash coproc and leftover coproc output

The idiom I finally settled on for processing a file one line at a time is:

coproc cat auto/etc/build.cfg
while read -u ${COPROC[0]} BRANCH TARGET SVNSRC SVNTAG BUILDTYPE DISTTYPE DISTARGS
do
    ... commands ...
done

I know for the simple case of cat I could just use input redirection. This is a simplified version, where the real one uses egrep to select a subset of lines.

Unfortunately this does not work.

$ cat test.sh
coproc cat auto/etc/build.cfg
while read -u ${COPROC[0]} BRANCH TARGET SVNSRC SVNTAG BUILDTYPE DISTTYPE DISTARGS
do
    echo hello
done

$ bash -x test.sh
+ read -u 63 BRANCH TARGET SVNSRC SVNTAG BUILDTYPE DISTTYPE DISTARGS
+ cat auto/etc/build.cfg
+ echo hello
hello
+ read -u BRANCH TARGET SVNSRC SVNTAG BUILDTYPE DISTTYPE DISTARGS
test.sh: line 2: read: BRANCH: invalid file descriptor specification

It appears that, even though there are 4 lines in the file, by the time of the second iteration the coprocess has vanished, along with its file descriptors, and the ${COPROC[*]} variable has become unset (note the missing fd in the second read).

To complicate matters, I'm working in both Cygwin and Linux (Fedora), and this exhibits slightly different behaviors in the two environments. In Linux I get the behavior described above. In Cygwin some commands (i.e. echo, which is a bash builtin) do not cause this problem. In both environments, running any external command kills the coprocess and tosses its descriptors.

I guess the real question here is:

In bash, how do I accomplish

while read (list of vars) from file
do
    one or more commands
done

The config files are short, so if I have to load the entire file into an array, that will work.

I'm really surprised that this is so hard in bash.

Was it helpful?

Solution

I am not sure why your usage of coproc is not working. Your example works for me with bash 4.2.8 on Mac OS X. Maybe certain versions of bash are buggy here.

It sounds like you could redirect from a process substitution instead of using a coprocess.

while read foo bar baz quux; do
    : use foo, bar, baz, quux in various commands
done < <(commands | that | generate --your lines-to-read)

This can be handy when your input is not already in a simple file where you could use plain redirection.


If you want to stick with coproc, you might be able to use an alternate formulation:

coproc { commands | that | generate --your lines-to-read ; }
while read foo bar baz quux; do
    : use foo, bar, baz, quux in various commands
done <&${COPROC[0]}

OTHER TIPS

One of the syntaxes for this is:

while read var1 var2 ... ; do
   # one or more commands
done < file
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top