修补 bash 函数

修补 bash 函数

我有一个 shell 函数(好吧,它是deactivate()由 Python virtualenv 定义的函数),我想通过在执行之前或之后插入一些语句来修补它。我的目标是拥有一个新deactivate()功能,它可以完成旧功能的功能,并且还可以做更多的事情。有办法做到这一点吗?

原始函数是从各个地方(各个 virtualenvs)动态定义的,因此在每个源处修改它并不是一个有吸引力的选择。

答案1

您可以创建一个比函数具有更高优先级的停用别名(如果足够的话)。因为您可以在之前运行命令,但在之后运行并不容易。

alias deactivate='before; deactivate'

或者简单地(更好)创建一个具有更简单名称的函数:

deact(){ [[ $somevar == true ]] && deactivate
         [[ $othervar == admin ]] && sudo deactivate
       }

或者任何你想实施的事情。是的,只会在定义的地方运行。它不是该词的替代品deactivate,也不适用于其他用户。

唯一的方法是创建一个名为 的可执行程序deactivate,但其优先级低于别名和函数。两者都需要未定义。

答案2

如果您的 shell 是bashzsh或者ksh93您可以利用typeset -f内置函数,它会显示函数的源代码:

# usage patch_func funcname before after
function patch_func {
        typeset nl=$'\n' lb={ src=`typeset -f "$1"` before=$2 after=$3
        src="${src/$lb/$lb$nl    $before$nl}"
        src="${src%\}*}$nl    $after$nl}"
        eval "$src"
}

例子:

$ deactivate(){ echo -n "{$0}"; for i; do echo -n " {$i}"; done; echo; }
$ patch_func deactivate 'echo before' 'echo after'
$ typeset -f deactivate
deactivate ()
{
    echo before;
    echo -n "{$0}";
    for i in "$@";
    do
        echo -n " {$i}";
    done;
    echo;
    echo after
}

这当然是相当脆弱的。

答案3

虽然这个答案并不直接适用于virtualenv使用 - 使用怎么样virtualenvwrapper?它基本上是virtualenv在类固醇上,负责环境管理。安装后,您将获得一组附加命令:

  • workon在不带参数调用时列出所有可用环境,并在使用 env 名称作为参数调用时激活 env,例如workon myenv激活 env myenv
  • mkvirtualenv myenv创建一个新的环境myenv
  • rmvirtualenv myenv将其删除。

但还有更多 -virtualenvwrapper定义了一组有用的钩子,您可以在其中实现自己的 envs 自定义逻辑,例如:

  • premkvirtualenv当环境被创建但尚未激活时执行;
  • postmkvirtualenv当创建并激活 env 时执行;
  • preactivate当 env 激活被触发时执行;
  • postactivate当 env 被激活时执行;
  • predeactivate当触发 env 停用时执行;
  • postdeactivate当 env 被停用时执行;

还有很多。例如,我有一个postmkvirtualenv安装ipython在新环境中的钩子:

$ cat $VIRTUALENVWRAPPER_HOOK_DIR/postmkvirtualenv
#!/bin/bash
# This hook is sourced after a new virtualenv is activated.

env=$(basename "$VIRTUAL_ENV")
logger -s -t "($env)" "installing ipython ..."
"$VIRTUAL_ENV/bin/pip" install ipython --quiet

要为 env 停用定义附加逻辑,您必须编写一个自定义 bash 脚本并将其内容放置到$VIRTUALENVWRAPPER_HOOK_DIR/predeactivate(如果您需要在 env 仍处于激活状态时运行您的东西)或$VIRTUALENVWRAPPER_HOOK_DIR/postdeactivate(如果您需要停用 env运行自定义代码)。

以供参考:virtualenvwrapper文档

有关钩子的完整列表,请参阅每用户定制

相关内容