En resumen todas las otras soluciones y parcialmente corregirlos, aquí está la solución que:
- no utiliza el doble
declare
- no necesita programas externos (como
tail
)
- no hace reemplazos inesperados
- es relativamente corto
- le protege frente a errores de programación habituales gracias a una correcta citando
Pero:
- Probablemente no funciona en las funciones recursivas, como el el nombre de función utilizado para la recursión dentro de la copia no se reemplaza. Conseguir ese derecho de reemplazo es una tarea demasiado compleja. Si desea utilizar tales reemplazos, puede probar esta respuesta https://stackoverflow.com/a/18839557 con
eval "${_//$1/$2}"
en lugar de eval "${_/$1/$2}"
(tenga en cuenta el doble //
). Sin embargo reemplazando el nombre produce un error en los nombres de funciones muy simples (como a
) y falla por recursividad calculada (como command_help() { case "$1" in ''|-help) echo "help [command]"; return;; esac; "command_$1" -help "${@:2}"; }
)
Todo combinado:
: rename_fn oldname newname
rename_fn()
{
local a
a="$(declare -f "$1")" &&
eval "function $2 ${a#*"()"}" &&
unset -f "$1";
}
ahora las pruebas:
somefn() { echo one; }
rename_fn somefn thatfn
somefn() { echo two; }
somefn
thatfn
salidas según sea necesario:
two
one
Ahora probar algunos casos más complicados, que todos dan los resultados esperados o se abstiene:
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
Se puede argumentar que sigue es todavía un error:
a(){ echo HW; }; rename_fn a " b "; echo $?; b
como debe fallar como " b "
no está un nombre de función correcto. Si realmente quiere esto, necesita la siguiente variante:
rename_fn()
{
local a
a="$(declare -f "$1")" &&
eval "function $(printf %q "$2") ${a#*"()"}" &&
unset -f "$1";
}
Ahora bien, esto atrapa este caso artificial. (Tenga en cuenta que printf
con %q
es una orden interna del bash
.)
Por supuesto se puede dividir esto en la copia + cambiar el nombre de la siguiente manera:
copy_fn() { local a; a="$(declare -f "$1")" && eval "function $(printf %q "$2") ${a#*"()"}"; }
rename_fn() { copy_fn "[email protected]" && unset -f "$1"; }
espero que esta es la solución 101%. Si necesita una mejora, coméntelo;)
Brillante! Gracias, bash wizard ;-) –
Parece que te perdiste ** {** en la línea 2: 'eval" $ (echo "orig_theirfunc() {"; declare -f theirfunc | tail -n +2) ''. O tal vez, en algunas configuraciones, declare que las impresiones abren una llave en una nueva línea. En ese caso, el script será más complicado. – Poma
Otra posibilidad que también trataría con funciones recursivas: 'eval '$ (declare -f theirfunc | sed'// btheirfunc \ b/orig_theirfunc/g)" ' –