[lug] Bletcherous pipe, FIXME!

Zan Lynx zlynx at acm.org
Thu Apr 2 14:58:27 MDT 2009

Andrew Gilmore wrote:
> I discovered this nastiness in something I recommended in a benchmark, and before I got it published, thought I'd see if anyone cared to try to fix it...
> The goal is to generate a sane default hosts.allow tcp wrappers only allowing hosts on the local networks.
> printf "ALL: localhost" >> /etc/hosts.allow              
> for I in `route -n |tail -n +3 |sed -e 's/ */ /g'| cut -f1,3 -d ' '
>    --output-delimiter=/ | grep -vE "^(0|169)" |sort -n`; do
>    printf ", $I" >> /etc/hosts.allow;
> done
> echo >> /etc/hosts.allow
> Ouch, I know.
> Anyone for a game of bash golf? :-)

Right away I see three opportunities to make it better.

Use echo instead of printf.  Echo is generally a shell builtin.

Instead of using a for I in `` loop, put that pipeline in front of a 
while read x; do loop.

Instead of using >> /etc/hosts.allow inside the loop, put it after the 
done.  All the output of the loop will be redirected and the file opened 
only once.

Even better, put the whole thing into a subshell with ( ) and redirect 
the output of it all at once.

So it might look like this:

    echo -n "ALL: localhost"
    route -n | tail -n +3 | sed -e 's/  */ /g' \
       | cut -f1,3 -d ' ' --output-delimiter=/ \
       | grep -vE "^(0|169)" \
       | sort -n \
    | while read I
       echo -n ", $I"
) >> /etc/hosts.allow

Notice that I also discovered the sed was wrong.  It has to be two 
spaces and then the star.
Zan Lynx
zlynx at acm.org

"Knowledge is Power.  Power Corrupts.  Study Hard.  Be Evil."

More information about the LUG mailing list