0

I've got a working global_exit i copied from somewhere, it's for two command exits. Renaming 'echo' to 'ech' to force a failure allows me to test all the permutations work - and they do here:

echo "$USER $(date +%F)" |& tee info.log
info_exit=${PIPESTATUS[0]}
echo "$USER $(date +%F)" |& tee list.log
list_exit=${PIPESTATUS[0]}

global_exit=$(( info_exit > list_exit ? info_exit : list_exit ))

if [ ${global_exit} = "0" ]; then
echo ">> SUCCESS <<"
elif [ ${global_exit} = "1" ]; then
echo ">> WARNINGS <<"
else
echo ">> FAILED <<"
fi
exit

How can i expand that to three RCs? I haven't been able to find the rules around how to use this feature. I just guessed using the below, but it doesn't work across all permutations of the same test (one-by-one rename just one echo to ech to force a failure):

echo "$USER $(date +%F)" |& tee info.log
info_exit=${PIPESTATUS[0]}
echo "$USER $(date +%F)" |& tee list.log
list_exit=${PIPESTATUS[0]}
echo "$USER $(date +%F)" |& tee check.log
check_exit=${PIPESTATUS[0]}

global_exit=$((( info_exit > list_exit > check_exit ? info_exit : list_exit > check_exit )))

if [ ${global_exit} = "0" ]; then
echo ">> SUCCESS <<"
elif [ ${global_exit} = "1" ]; then
echo ">> WARNINGS <<"
else
echo ">> FAILED <<"
fi
exit

Thanks :)

0
1

One possibility to check multiple return codes together for 0, 1 and all the rest is to combine the return codes:

echo "$USER $(date +%F)" |& tee info.log
exit_code=$((exit_code | PIPESTATUS[0]))
echo "$USER $(date +%F)" |& tee list.log
exit_code=$((exit_code | PIPESTATUS[0]))
echo "$USER $(date +%F)" |& tee check.log
exit_code=$((exit_code | PIPESTATUS[0]))

if (( 0 == exit_code )); then
  echo ">> SUCCESS <<"
elif (( 1 == exit_code )); then
  echo ">> WARNING <<"
else
  echo ">> FAILED <<"
fi

With this approach you can't distinguish between the exit codes and potentionally multiple return codes may occur but for a general OK / not OK return code it should be enough.

3
  • If i understand you right, this one also serves my purposes (along with Fubar's. I really just need the highest number to return the warning or error so i can investigate. It's simpler than Fubar's, but maybe less extensible? If i could bother you, I'd like to know more about the difference between them (see my comment in the other solution). Thanks :) – Derek Apr 17 '20 at 19:05
  • This answer is actually more efficient, as it doesn't require the storage of values other than the highest resulting error code. It also cuts the conditionals required down to just the final test for success, warn, fail. Since you don't use the individual status codes, not storing them doesn't hurt anything. – Fubar Apr 17 '20 at 19:28
  • a further caveat of my solution is that the original return codes are "destroyed" if more than one function returns with a non-zero exit-code following will happen: function1 returns with 38, function2 returns with 1: the resulting exit code would be 39 because of the bit-wise OR. – noAnton Apr 20 '20 at 5:47
1

If I have the intent correct and you wish to continue with the code as written, change this:

global_exit=$((( info_exit > list_exit > check_exit ? info_exit : list_exit > check_exit )))

to this:

global_exit=$((( info_exit > list_exit > check_exit ? info_exit : list_exit > check_exit ? list_exit : check_exit )))

As you have it, if info_exit is largest it works fine. If not, it sets global_exit to a 0 or 1 depending on whether list_exit > check_exit or not. With the additional condition added it will be set to the greater of list_exit or check_exit.

2
  • Thankyou. This seems to work. I also tried it with just two parenthesis (( ... )) and that seemed to work too. Do you know why? Also, while i do like the readability - the reason i took this approach because i got the idea from someone else's script - not because i knew what i wanted except the final output :), Do you know what the advantage of it is over noAnton's answer below? That one also works for my purposes and is simpler but perhaps doesn't quite have the result delineation if you needed it? – Derek Apr 17 '20 at 19:01
  • yeah... hadn't really noticed that. You added the third paren in your code, so I just copy/pasted. A single paren would cause it to try to execute unix-y commands, and would fail with an error "info_exit: command not found". The second paren puts turns it into the conditional needed for the syntax of the conditional execution. The third paren doesn't hurt anything, but isn't necessary. noAnton's answer, as he mentioned, doesn't save the individual exit codes as the original does. It uses bitwise ops to copy the highest value. As you don't use the codes, either way would be effective. – Fubar Apr 17 '20 at 19:24
1

You could use a function and check all status codes of PIPESTATUS and save the highest value.

#!/bin/bash

max_exit=0

set_max_exit() {
  for i in "${PIPESTATUS[@]}"; do
    [ "$i" -gt "$max_exit" ] && max_exit=$i
  done
}

echo | grep x   # exit 1
set_max_exit

ech             # exit 127
set_max_exit

ls adfds        # exit 2
set_max_exit

if [ "$max_exit" -eq 0 ]; then
  echo ">> SUCCESS <<"
elif [ "$max_exit" -eq 1 ]; then
  echo ">> WARNING <<" >&2
else
  echo ">> FAILED <<" >&2
fi

exit "$max_exit"

Output:

$ ./script.sh
./script.sh: line 14: ech: command not found
ls: cannot access 'adfds': No such file or directory
>> FAILED <<
$ echo $?
127
1
  • The solutions from Fubar and noAnton seem to work for my purposes. This one seems like it can provide more information which is cool and maybe one day for different purpose i'll use it. But for now, it's a bit scary :D Thanks :) – Derek Apr 17 '20 at 19:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.