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"

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

    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"


  • 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

# Save the old command_not_found_handle for reuse
renameFunction command_not_found_handle __PREVIOUS_COMMAND_NOT_FOUND_HANDLE

command_not_found_handle () {
    if [ $? -gt 0 ]; then

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