Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question

2 Answers 2

up vote 11 down vote accepted

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.

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

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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