总结了所有的其他解决方案和部分纠正他们,这里是一个解决方案:
- 不使用
declare
两次
- 不需要外部程序(如
tail
)
- 确实没有意外替换
- 较短
- 保护您免受通常的编程错误感谢纠正报价
但是:
- 它可能不会在递归函数的工作,因为复制中用于递归的函数名称不会被替换。获得这样的替代权是一项非常复杂的任务。如果你想使用这样的替换,你可以试试这个回答https://stackoverflow.com/a/18839557 whith
eval "${_//$1/$2}"
而不是eval "${_/$1/$2}"
(注意双//
)。然而更换名字太简单函数名失败(如a
),也未能为计算递归(如command_help() { case "$1" in ''|-help) echo "help [command]"; return;; esac; "command_$1" -help "${@:2}"; }
)
一切组合:
: rename_fn oldname newname
rename_fn()
{
local a
a="$(declare -f "$1")" &&
eval "function $2 ${a#*"()"}" &&
unset -f "$1";
}
现在测试:
somefn() { echo one; }
rename_fn somefn thatfn
somefn() { echo two; }
somefn
thatfn
按要求输出:
two
one
现在尝试一些更复杂的情况,这都产生预期的结果或失败:
rename_fn unknown "a b"; echo $?
rename_fn "a b" murx; echo $?
a(){ echo HW; }; rename_fn " a " b; echo $?; a
a(){ echo "'HW'"; }; rename_fn a b; echo $?; b
a(){ echo '"HW"'; }; rename_fn a b; echo $?; b
a(){ echo '"HW"'; }; rename_fn a "b c"; echo $?; a
人们可以争辩说,下面仍然是一个错误:
a(){ echo HW; }; rename_fn a " b "; echo $?; b
,因为它应该失败,因为" b "
不一个正确的函数名称。如果你真的需要这个,你需要下面的变种:
rename_fn()
{
local a
a="$(declare -f "$1")" &&
eval "function $(printf %q "$2") ${a#*"()"}" &&
unset -f "$1";
}
现在,这也捕捉到了这个假象。 (请注意:printf
与%q
是bash
内置)
当然你也可以拆分此成复制+改名这样的:
copy_fn() { local a; a="$(declare -f "$1")" && eval "function $(printf %q "$2") ${a#*"()"}"; }
rename_fn() { copy_fn "[email protected]" && unset -f "$1"; }
我希望这是101%的解决方案。如果需要改进,请发表评论;)
太棒了!谢谢你,bash向导;-) – 2009-09-02 18:14:05