Bash help requested: Capturing command errors within pipes

Daniel B. Thurman dant at cdkkt.com
Fri Mar 20 01:55:54 UTC 2009


Cameron Simpson wrote:
> On 19Mar2009 12:19, Daniel B. Thurman <dant at cdkkt.com> wrote:
>   
>> OK, I found out why I had a problem!
>>
>> I setup an intentional sed error:
>> $ (re="-e '\'s/b/h/'"; echo "boo" | sed $re | echo "done"; echo  
>> ${PIPESTATUS})
>> done
>> sed: -e expression #1, char 1: unknown command: `''
>> 0
>>     
>
> [ I'm sure you know everything I say below based on previous posts, but
>   it seems worth saying purely for other readers...
> ]
>
> Ok, but I strongly recommend you never us a regexp unquoted - the
> necessary backslash nesting gets nasty real fast. A better way is like
> this:
>
>   re='s/b/h/'
>   sed -e "$re"
>
> or for complex stuff, write a file called "sedf" (for example)
> containing a full sed script:
>
>   s/b/h/
>   /foo/d
>   /bah/b again
>
> etc. Then:
>
>   sed -f sedf
>
> The point here, unrelated to the pipe exit status issue, is to keep the
> sed stuff easy to write and undamaged by shell substitution.
>
> On the pipe stuff, another approach (less convenient than PIPESTATUS),
> is a flag approach like you original attempt, but using files:
>
>   badness=/tmp/foo$$bad
>   { x || touch $badness; } \
>   | { y || touch $badness; } \
>   | { z || touch $badness; }
>   if [ -f $badness ]
>   then
>     rm $badness
>     echo badness happened >&2
>   fi
>
> It has the advantage of working in non-pipe circumstances (nested
> subshells, etc).
>
> Cheers,
>   
Another person sent me private email
warning of the double-quotes, but thanks
for your information, it is interesting!

This is what I ended up doing, so please give
your constructive critiques, if you so like?

TRACKER="Tracker.log"
SFILE="Bad_Hosts_File.txt"
TFILE="Bad_Hosts_File_$$.txt"
pat="EACC"
re1="-e '/$pat/s/^.*Received:\[from\s\+\(.*\)\s\+(.*/\1/'"
re2="-e '/^.*cdkkt.com$/d'"
rex="sed $re1 $re2"

echo -en "\033[0;36m>> \033[0;35mExtracting data from:\n \
  [\033[0;34m${TRACKER}\033[0;35m and appending to\n \
  [\033[0;34m${TFILE}\033[0;35m]\033[0m"

out=$(grep "$pat" "${TRACKER}" | \
          eval "$rex" | sort -n | \
          uniq >> "${TFILE}"); ret="$?";

if [ "$ret" -gt 0 ] || \
   [ "$PIPESTATUS[0]" -gt 0 ] || \
   [ "$PIPESTATUS[1]" -gt 0 ] || \
   [ "$PIPESTATUS[2]" -gt 0 ] || \
   [ "$PIPESTATUS[3]" -gt 0 ]; then
   echo -e " \033[0;31mFailed.\n   \
   \033[0;35m-- ErrorStatus:<ret=$ret>,\
  PipeStatus:<$PIPESTATUS[@]>\n\
  -- out:<$out>\033[0m"
   echo -e "\033[0;31m>> \033[0;31m$PROG exited.\033[0m\n"
   exit 1
fi
echo -e " \033[0;32mDone.\033[0m";

I guess the ugly part is the multiple $PIPESTATUS[n]
in the if statement test block. but perhaps this is the best
I can do?

Dan




More information about the fedora-list mailing list