# -*- mode: sh; -*-
#
# Public domain
#
# Written by Aleksey Cheusov <vle@gmx.net>
# 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
}