保存函数bash的旧值,以便稍后调用它

时间:2015-08-04 00:17:16

标签: bash

是否可以保存旧函数(名为foo),以便您可以在新函数(也称为foo)中调用它,可能来自不同的名称,或者?

为了使这个具体化,这里特别是我正在尝试做的事情:

在bash中,command_not_found_handle是一个函数,如果定义了,只要bash找不到用户试图运行的命令就会调用它。例如,Ubuntu使用它来建议可以安装的软件包:

$ pv
The program 'pv' is currently not installed. You can install it by typing:
sudo apt-get install pv

这真是很好,我想保持这种行为。但是,我喜欢添加另一个command_not_found句柄,它只是使用用户输入的任何命令行运行给定的DEFAULT_COMMAND,如下所示:

$ DEFAULT_COMMAND=git
$ status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working
directory)

        modified:   .bashrc
        modified:   .gitconfig
        modified:   .vimrc

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        .bash_profile
        .gitglobalignore
        .gvimrc
        node_modules/

no changes added to commit (use "git add" and/or "git commit -a")

我已经有了上述功能,它就像一个梦想;但是,使用它覆盖默认的Ubuntu command_not_found句柄,当我不记得给定可执行文件的包名时,它可以很方便。

我如何同时获得两者?谢谢!

注意:显而易见的解决方案是在我的脚本中查找并复制Ubuntu内置command_not_found逻辑;但这并不理想,因为这意味着我必须在以后手动更新它,当Ubuntu改变他们做事的方式时。如果可能的话,我希望有更通用的东西。

编辑:最好不要诉诸字符串操作,可以通过将函数的 text 保存到变量,修改它,然后eval来完成它

1 个答案:

答案 0 :(得分:1)

根据Barmar的建议,我能够实现可行的 解。以下函数可用于重命名任意 bash函数改为其他名称。

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"
}

注释

  • 最后一行

    unset "$oldName"
    

    是可选的 - 没有它,它就变成了“复制功能”实用程序。

  • 模式替换适用于递归函数(如果是) 更改为以下内容(请注意//):

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

    但是,如果函数名是某个子字符串,则会失败 在定义中的其他内容。由于递归在shell中比较少见 脚本,我采取了不那么脆弱的方法。

  • 引用正确,尽管对于SO语法过于复杂 荧光笔。 (引用也是不必要的,除非你喜欢 与$IFS一起玩。)

为了完整起见,以下是我使用此功能的方法:

# 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就会调用{p> bash 用户指定的程序或命令。它接收它作为它的论据 整个命令行。

此函数尝试将命令行作为“子命令”执行 给定的DEFAULT_CMD。如果它没有成功,它会尝试旧的 command_not_found_handle