Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to write a wrapper function that runs commands and logs their exit code

Tags:

bash

shell

unix

I currently use this function to wrap executing commands and logging their execution, and return code, and exiting in case of a non-zero return code.

However this is problematic as apparently, it does double interpolation, making commands with single or double quotes in them break the script.

Can you recommend a better way?

Here's the function:

do_cmd()
{
    eval $*
    if [[ $? -eq 0 ]]
    then
        echo "Successfully ran [ $1 ]"
    else
        echo "Error: Command [ $1 ] returned $?"
        exit $?
    fi
}
like image 244
Tom Feiner Avatar asked Dec 16 '08 17:12

Tom Feiner


2 Answers

"$@"

From http://www.gnu.org/software/bash/manual/bashref.html#Special-Parameters:

@

Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" .... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed).

This means spaces in the arguments are re-quoted correctly.

do_cmd()
{
    "$@"
    ret=$?
    if [[ $ret -eq 0 ]]
    then
        echo "Successfully ran [ $@ ]"
    else
        echo "Error: Command [ $@ ] returned $ret"
        exit $ret
    fi
}
like image 149
Douglas Leeder Avatar answered Oct 12 '22 05:10

Douglas Leeder


Additional to "$@" what Douglas says, i would use

return $?

And not exit. It would exit your shell instead of returning from the function. If in cases you want to exit your shell if something went wrong, you can do that in the caller:

do_cmd false i will fail executing || exit
# commands in a row. exit as soon as the first fails
do_cmd one && do_cmd && two && do_cmd three || exit

(That way, you can handle failures and then exit gracefully).

like image 43
Johannes Schaub - litb Avatar answered Oct 12 '22 06:10

Johannes Schaub - litb