總結了所有的其他解決方案和部分糾正他們,這裏是一個解決方案:
- 不使用
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