I want to loop over the output of a command without creating a sub-shell or using a temporary file.

The initial version of of my script looked like this, but this doesn't work since it creates a subshell, and the exit command terminates the subshell instead of the main script which is required. It is part of a much larger script to configure policy routing, and it is halt the execution if it detects a condition that will cause routing to fail.

sysctl -a 2>/dev/null | grep '\.rp_filter' | while read -r -a RPSTAT ; do

  if [[ "0" != "${RPSTAT[2]}" ]] ; then
    echo >&2 "RP Filter must be disabled on all interfaces!"
    echo >&2 "The RP filter feature is incompatible with policy routing"
    exit 1

So one of the suggested alternatives is to use a command like this to avoid the subshell.

while read BLAH ; do echo $BLAH; done </root/regularfile

So it seems to me that I should also be able use a command like this to avoid the subshell and still get the output from the program I want.

while read BLAH ; do echo $BLAH; done <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Unfortunately, using that command results in this error.

-bash: syntax error near unexpected token `<(sysct ...

I get really confused since this does work.

cat <(sysctl -a 2>/dev/null | grep '\.rp_filter')

I could save the output of that command to a temporary file, and use redirect the on the temporary file, but I wanted to avoid doing that.

So why is the redirection giving me an error, and do I have any options other then creating a temporary file?


You missed a <. Should be:

while read BLAH ; do echo $BLAH; done < <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Think of <(sysctl -a 2>/dev/null | grep '\.rp_filter') being a file.

| improve this answer | |
  • Thanks a lot. Just for my edification, can point me at a man page, help, or web page, that documents this? I couldn't get Google to point me at anything useful while trying to search for this. – Zoredache Jan 14 '11 at 17:55
  • 2
    Google "process substitution". e.g. tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB – dogbane Jan 14 '11 at 17:59
  • It should be noted that the <() substitution uses file descriptors and on some operating systems will transparently create & use temporary files. – ewindisch Jan 14 '11 at 18:21
  • @Zoredache: Simply search for <( in the bash manual (it's under “process substitution”). – Gilles 'SO- stop being evil' Jan 14 '11 at 22:23
  • @ewindisch, if a tool transparently creates a tempfile that is fine, I just didn't want to manually create one, when I was pretty sure I didn't need to. – Zoredache Jan 14 '11 at 22:26

For a few more alternatives if anyone comes here again...

Depending on the shell, you could probably use set -o errexit to have the parent shell exit when a command (including a subshell) exits non-zero without being trapped in an if block or a trailing && or ||, as in

/bin/false || echo "ignoring error"

Or, you could have the subshell signal the parent using kill and the $PPID environment variable, if available.

Or you could move the while block into a function and return 0/1 (explicitly return 0 after the while block) and just do your pipeline like sysctl | grep | function || exit. I suppose you could put the returns in the inline block, too, but functions are your friend. ;)

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.