Pipe filtering

Hi,

The thing is that sometimes I need to filter an arbitrary output given a condition (think on the "filter" function present on some programming languages) from the shell (I use sh/bash). I tried this:

#!/bin/sh
# Usage: filter command [options_for_xargs]
COMMAND=$1
shift 1
xargs "$@" -I "{}" sh -c "if $COMMAND; then echo {}; fi"

And now, if I want to get all the non-executable files under /etc, I can run this:

$ find /etc -type f -print0 | filter "! test -x {}" -0
/etc/fam.conf
/etc/cups/cupsd.conf
/etc/cups/snmp.conf
/etc/cups/lpoptions
/etc/cups/mime.types
....

So the question is... is there any better/faster way of doing this generic filter with sh/bash?

thanks!

FWIW: find supports the -mode option - you use this to test permissions bits.

Your generic filter invokes a whole new process, which may not be all that efficient when compared to other options available to a command. It is an interesting idea, though. Have you considered the concept of a coprocess using named pipes?

See the bash FAQ here:
ftp://ftp.cwru.edu/pub/bash/FAQ

Yes, I'm aware of this, it was just an example.

Certaintly. A pure bash solution (less versatile as it does not use xargs) I though was as simple as:

#!/bin/sh
COMMAND=$1
while read LINE; do
     eval "${COMMAND/\{\}/$LINE}" && echo $LINE
done

No, I didn't, how could it be written? anyway you gave me an idea: taking the 'sh' out of xargs and run it on a pipe:

xargs "$@" -I "{}" echo "$COMMAND && echo {}" | sh

It's not as fast as the pure bash solution, but is cheaper to run "echo"s than "sh"s processes. If it was possible to for xargs to output the command without actually running it, it should really fast (there is no such option AFAIK)

thanks

The FAQ shows you how to write coprocesses with named pipes.