score:1

Based on Barmar's suggestion, I was able to implement a workable solution. The following function can be used to rename an arbitrary bash function to another name.

renameFunction () {
    local oldName="$1"; shift
    local newName="$1"

    local definition="$(declare -f "$oldName")"
    if [[ $? -gt 0 ]]; then
        echo >&2 "renameFunction: $oldName is not a function"
        return
    fi

    if declare -f  "$newName" >/dev/null 2>/dev/null; then
        echo >&2 "renameFunction: $newName is already defined"
        return
    fi

    eval "$(echo "${definition/"$oldName"/"$newName"}")"
    # Does not work for recursive functions (like "//" would), but also
    # doesn't break if $oldName is a substring of something else

    unset "$oldName"
}

Notes

  • The last line

    unset "$oldName"
    

    is optional — and without it, this becomes a "copy function" utility.

  • The pattern substitution would work for a recursive function if it were changed to the following (note the //):

    eval "$(echo "${definition//"$oldName"/"$newName"}")"
    

    However, this fails if the function name is a substring of something else within the definition. Since recursion is relatively rare in shell scripts, I took the less brittle approach.

  • The quoting is correct, despite being too complex for the SO syntax highlighter. (The quoting is also unnecessary, unless you like to play with $IFS.)


For completeness' sake, here's how I'm using this function:

# The DEFAULT_CMD is the command to run if the command line could
# not be understood.  Set the DEFAULT_CMD to git, once; the user can
# change it at any time
DEFAULT_CMD=git

# Save the old command_not_found_handle for reuse
renameFunction command_not_found_handle __PREVIOUS_COMMAND_NOT_FOUND_HANDLE

command_not_found_handle () {
    eval '"$DEFAULT_CMD" $DEFAULT_CMD_PREFIX_ARGS "$@" $DEFAULT_CMD_POSTFIX_ARGS'
    if [ $? -gt 0 ]; then
        __PREVIOUS_COMMAND_NOT_FOUND_HANDLE "$@"
    fi
}
export DEFAULT_CMD

command_not_found_handle is called by bash whenever it cannot find program or command that the user specified. It receives as its arguments the entire command-line.

This function tries to execute the command-line as a "sub command" of the given DEFAULT_CMD. If it does not succeed, it tries the old command_not_found_handle


Related Query

More Query from same tag