Reputation: 1173
I have the following script:
#!/bin/bash
set -e
function do_it {
rm this-file-does-not-exit
echo "Continuing ..."
echo "Done ..."
return 0
}
if do_it ; then
echo "Success"
else
echo "Error"
fi
echo "End of script"
Which produces:
rm: cannot remove 'this-file-does-not-exit': No such file or directory
Continuing ...
Done ...
Success
End of script
The function is not aborted because running the function in the if
statement disables set -e
for the function (and can not be enabled). This is not what I want.
Running the function outside the if
statement, and collecting the result, is not possible, because in this situation the complete script is aborted if the function fails:
#!/bin/bash
set -e
function do_it {
rm this-file-does-not-exit
echo "Continuing ..."
echo "Done ..."
return 0
}
do_it
if $? ; then
echo "Success"
else
echo "Error"
fi
echo "End of script"
Produces:
rm: cannot remove 'this-file-does-not-exit': No such file or directory
I would like the following:
This can be implemented as follows:
#!/bin/bash
set -e
function do_it {
rm this-file-does-not-exit || return $?
echo "Continuing ..." || return $?
echo "Done ..." || return $?
return 0
}
if do_it ; then
echo "Success"
else
echo "Error"
fi
echo "End of script"
Which produces what I want:
rm: cannot remove 'this-file-does-not-exit': No such file or directory
Error
End of script
But this makes the implementation of the function completely unreadable: each line must be followed with a || return $?
Is there another way of aborting a function, and only the function, whenever an statement in the function fails?
Upvotes: 6
Views: 856
Reputation: 1391
You can use "pipefail" to get the return code of the last executed command in the pipe. I wouldn't say it looks much better than your code, but at least it's shorter.
#!/bin/bash
set -ep
function do_it {
rm this-file-does-not-exit &&
echo "Continuing ..." &&
echo "Done ..."
return $?
}
if do_it ; then
echo "Success"
else
echo "Error"
fi
echo "End of script"
In this case function will stop executing right after first failed command (rm) and the result will be the return code of the last command in the pipeline. If "rm <filename>" will be successful, both echoes should work, and the return code will be 0.
Output:
$ touch this-file-does-not-exit
$ ./script-return.sh
Continuing ...
Done ...
Success
End of script
$ ./script-return.sh
rm: cannot remove 'this-file-does-not-exit': No such file or directory
Error
End of script
Upvotes: 2
Reputation: 3461
Nice question :D What you can do is create a function that parses functions and appends | return $?
if a command fails.
#! /bin/bash
function _exec {
local func=$1
[[ ! -z $func ]] || exit 1
local data="$(typeset -f $1 | sed '1,2d;$d');"
while read -d ';' cmd; do
eval "$cmd" || return $?
done <<<"$data"
return 0
}
function _test {
local ret=$1
echo -n "[ RESULT ]: "
if [[ $ret -ne 0 ]]; then
echo "failure"
else
echo "success"
fi
}
function _fail {
rm thisfilewillnevereverexistonmyfilesystemsoidonthavetomakesureitdoesnt.txt
echo "hello"
echo 2 3 \
multiline also works
}
function _pass {
true
echo "Hello world"
}
_exec _fail
_test $?
_exec _pass
_test $?
exit 0
How it basically works is you let _exec
execute the functions that may not fail. It retrieves the content of the function given as it's parameter and executes it with eval
. Note that if you would execute false
in _true
, the _exec
function will fail also.
Hope this works out for you.
Upvotes: 1
Reputation: 77030
I'm not very good with bash scripting and it would take me a lot of effort to implement my following thought, but I think this should work:
Upvotes: 1