9

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
  fi
done

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?

1

2 Answers 2

14

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.

5
  • 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, 2011 at 17:55
  • 2
    Google "process substitution". e.g. tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB
    – dogbane
    Jan 14, 2011 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, 2011 at 18:21
  • @Zoredache: Simply search for <( in the bash manual (it's under “process substitution”). Jan 14, 2011 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, 2011 at 22:26
0

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. ;)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .