# -*- mode: sh; -*- # # Public domain # # Written by Aleksey Cheusov # based on the code from FAQ of comp.unix.shell newsgroup # # Set of shell functions for running pipe and checking # exit status of ALL programs, not only last one. # # Version 0.6.0 # # __shquote (){ __cmd=`printf '%s\n' "$1" | sed "s|'|'\\\\\''|g"` printf "%s\n" "'$__cmd'" } __pipestatus_err_msg (){ if test "$PIPESTATUS_VERBOSE"; then echo "Pipe failed, pipestatus_all='$pipestatus_all'" 1>&2 fi } # run pipe and set pipestatus_1, pipestatus_2, ... and pipesize variables # Example: runpipe_base prog1 arg11 arg12 '|' prog2 arg21 arg22 '|' prog3 # Always return zero exit status runpipe_base (){ # pipesize=0 # whole command __pipestatus_com= # token count __pipestatus_k=1 # program in pipe (between |) __pipestatus_l= # counter __pipestatus_j=1 # generating whole command for __pipestatus_a in "$@"; do if [ "_$__pipestatus_a" = '_|' ]; then __pipestatus_com="$__pipestatus_com { if $__pipestatus_l 3>&-"'; then echo "pipestatus_'$__pipestatus_j'=0" 1>&3 else echo "pipestatus_'$__pipestatus_j'=$?" 1>&3 fi } 4>&- | ' __pipestatus_j=`expr $__pipestatus_j + 1` __pipestatus_l= else __pipestatus_l="$__pipestatus_l `__shquote \"$__pipestatus_a\"`" fi __pipestatus_k=`expr $__pipestatus_k + 1` done __pipestatus_com="if $__pipestatus_com $__pipestatus_l 3>&- 1>&4 4>&-"'; then echo "pipestatus_'"$__pipestatus_j"'=0" else echo "pipestatus_'"$__pipestatus_j"'=$?" fi' # # echo "$__pipestatus_com" # '|| true' - trick for 'set -e' exec 4>&1 eval `exec 3>&1; eval "$__pipestatus_com" || true` exec 4>&- # pipesize=$__pipestatus_j # pipestatus_all __pipestatus_j=2 pipestatus_all=$pipestatus_1 while [ "$__pipestatus_j" -le "$pipesize" 2>/dev/null ]; do eval "pipestatus_all=\"$pipestatus_all \$pipestatus_$__pipestatus_j\"" __pipestatus_j=`expr $__pipestatus_j + 1` done return 0 } # returns zero exit status if ALL progs in pipe return zero check_status0 (){ __pipestatus_j=1 while [ "$__pipestatus_j" -le "$pipesize" ]; do eval "[ \$pipestatus_$__pipestatus_j -eq 0 ]" || { __pipestatus_err_msg return 1 } __pipestatus_j=`expr $__pipestatus_j + 1` done return 0 } # returns zero exit status if ALL progs in pipe return zero runpipe0 (){ runpipe_base "$@" check_status0 } # match all statuses with the pattern # example: check_status_re '0 . 0' # . means "any status" check_status_re (){ __pipestatus_re=`echo $1 | sed 's/[.]/[0-9][0-9]*/g'` __pipestatus_j=1 __pipestatus_ps= while [ "$__pipestatus_j" -le "$pipesize" ]; do eval '__pipestatus_ps="$__pipestatus_ps ${pipestatus_'$__pipestatus_j'}"' __pipestatus_j=`expr $__pipestatus_j + 1` done # trick for set -e if echo "$__pipestatus_ps" | grep -E "^ $__pipestatus_re"'$' > /dev/null then __pipestatus_ret=0 else __pipestatus_ret=$? __pipestatus_err_msg fi # egrep not found? case "$__pipestatus_ret" in 0|1) ;; *) exit 2; # fatal error with egrep esac return $__pipestatus_ret } # match all statuses with the pattern # example: runpipe_re '0 . 0' prog1 '|' prog2 '|' prog3 # . means "any status" runpipe_re (){ __pipestatus_re="$1" shift runpipe_base "$@" check_status_re "$__pipestatus_re" } # return exit code of the last program in pipe check_status (){ eval return '$pipestatus_'${pipesize} } # similar to plain pipe but set 'pipestatus_XX' and 'pipesize' variables runpipe (){ runpipe_base "$@" check_status }