开发者

How to handle errors reliably in a shell function called as a condition?

开发者 https://www.devze.com 2023-03-17 21:33 出处:网络
Using bash 4.1.5: #!/bin/bash set -e foo() { false echo \"argh, I don\'t want to get there! What about set -e?!\"

Using bash 4.1.5:

#!/bin/bash

set -e

foo()
{
        false
        echo "argh, I don't want to get there! What about set -e?!"
}

foo && echo "ok"

This yields the following output:

argh, I don't want to get there! What about set -e?!
ok

This issue occurs whenever foo is called as a condition (i.e inside if, while, &&, ||, etc.). foo behaves correctly if called as a simple command.

I find this behavior surprising and quite frankly dangerous, because this means that the behavior of a bash funct开发者_Go百科ion changes depending on how it is called. For example, even something as simple as foo and foo && true will not yield the same results. This is very troubling! One can only imagine how much chaos this could cause if foo is doing sensitive operations...

Is there any workaround I could use to avoid this kind of situation?


Why don't you make foo() return a non-zero exit code if it fails?

foo(){
    return 1
    echo "argh, I don't want to get here! What about set -e?!"
}


The behavior you describe is expected, and quite necessary. Consider a function like:

word_is_in_file() {
   grep $1 $2 > /dev/null
}

Now, consider a script that uses this function (sorry, this example is a bit contrived since a real script would probably just invoke grep directly) to make a decision:

if word_is_in_file $word $file; then
  do_something
else
  do_something_else
fi

The definition of the function may be buried in a library of shell functions that the author never sees. The author does not consider the grep failure to be a failure, and would be very baffled if the script terminated because of it.

A way to get the semantics you desire is to do something like:

foo() {
   # This function will abort if errors are encountered, but 
   # the script will continue
   sh -e -c '
   false
   echo not reached'
}

foo && echo not reached
echo reached
foo
echo not reached

The semantics of set -e are also set to not abort the script in the "foo && ..." case for the same reason. It allows branching.

0

精彩评论

暂无评论...
验证码 换一张
取 消