Necesito pasar una función como parámetro en Bash. Por ejemplo, el siguiente código:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
Debería generar:
before
Hello world
after
Sé eval
que no es correcto en ese contexto, pero eso es solo un ejemplo :)
¿Alguna idea?
function
palabra, no podrá acceder a esos métodos internos hasta que ejecute el método de nivel superior.No creo que nadie haya respondido bien a la pregunta. No preguntó si podía hacer eco de las cuerdas en orden. Más bien, el autor de la pregunta quiere saber si puede simular el comportamiento del puntero de función.
Hay un par de respuestas que se parecen mucho a lo que haría yo, y quiero ampliarlas con otro ejemplo.
Del autor:
function x() { echo "Hello world" } function around() { echo "before" ($1) <------ Only change echo "after" } around x
Para expandir esto, tendremos la función x echo "Hola mundo: $ 1" para mostrar cuándo ocurre realmente la ejecución de la función. Pasaremos una cadena que es el nombre de la función "x":
function x() { echo "Hello world:$1" } function around() { echo "before" ($1 HERE) <------ Only change echo "after" } around x
Para describir esto, la cadena "x" se pasa a la función around () que echos "antes", llama a la función x (a través de la variable $ 1, el primer parámetro pasado a around) pasando el argumento "AQUÍ", finalmente echos después .
Como otro aparte, esta es la metodología para usar variables como nombres de funciones. Las variables realmente contienen la cadena que es el nombre de la función y ($ variable arg1 arg2 ...) llama a la función pasando los argumentos. Vea abajo:
function x(){ echo $3 $1 $2 <== just rearrange the order of passed params } Z="x" # or just Z=x ($Z 10 20 30)
da: 30 10 20, donde ejecutamos la función llamada "x" almacenada en la variable Z y pasamos los parámetros 10 20 y 30.
Arriba, donde hacemos referencia a funciones asignando nombres de variable a las funciones para que podamos usar la variable en lugar de conocer realmente el nombre de la función (que es similar a lo que podría hacer en una situación de puntero de función muy clásica en c para generalizar el flujo del programa pero antes -seleccionando las llamadas a la función que realizará en función de los argumentos de la línea de comandos).
En bash, estos no son punteros a funciones, sino variables que hacen referencia a nombres de funciones que luego usa.
fuente
()
, no iniciará un sub-shell?no hay necesidad de usar
eval
function x() { echo "Hello world" } function around() { echo "before" var=$($1) echo "after $var" } around x
fuente
No puede pasar nada a una función que no sean cadenas. Las sustituciones de procesos pueden simularlo. Bash tiende a mantener abierto el FIFO hasta que se completa un comando que se expande.
Aquí hay uno rápido y tonto
foldl() { echo $(($(</dev/stdin)$2)) } < <(tr '\n' "$1" <$3) # Sum 20 random ints from 0-999 foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)
Las funciones se pueden exportar, pero esto no es tan interesante como parece. Encuentro que es principalmente útil para hacer que las funciones de depuración sean accesibles para scripts u otros programas que ejecutan scripts.
( id() { "$@" } export -f id exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi' )
id
todavía solo obtiene una cadena que resulta ser el nombre de una función (importada automáticamente desde una serialización en el entorno) y sus argumentos.El comentario de Pumbaa80 a otra respuesta también es bueno (
eval $(declare -F "$1")
), pero es principalmente útil para matrices, no funciones, ya que siempre son globales. Si ejecutara esto dentro de una función, todo lo que haría es redefinirlo, por lo que no tiene ningún efecto. No se puede utilizar para crear cierres o funciones parciales o "instancias de función" dependientes de lo que sea que esté vinculado en el ámbito actual. En el mejor de los casos, esto se puede usar para almacenar una definición de función en una cadena que se redefine en otro lugar, pero esas funciones solo se pueden codificar a menos que, por supuesto,eval
se utilicenBásicamente, Bash no se puede usar así.
fuente
Un mejor enfoque es usar variables locales en sus funciones. Entonces, el problema se convierte en cómo hacer llegar el resultado a la persona que llama. Un mecanismo es utilizar la sustitución de comandos:
function myfunc() { local myresult='some value' echo "$myresult" } result=$(myfunc) # or result=`myfunc` echo $result
Aquí el resultado se envía a la salida estándar y la persona que llama utiliza la sustitución de comandos para capturar el valor en una variable. Luego, la variable se puede usar según sea necesario.
fuente
Deberías tener algo parecido a:
function around() { echo 'before'; echo `$1`; echo 'after'; }
Entonces puedes llamar
around x
fuente
eval es probablemente la única forma de lograrlo. El único inconveniente real es el aspecto de seguridad, ya que debe asegurarse de que no se pase nada malicioso y solo se invoquen las funciones que desea que se llamen (además de verificar que no tenga caracteres desagradables como ';' en él también).
Entonces, si eres el que llama al código, entonces eval es probablemente la única forma de hacerlo. Tenga en cuenta que hay otras formas de evaluación que probablemente también funcionarían con subcomandos ($ () y ``), pero no son más seguras y son más caras.
fuente
eval $1
llamaría a una función usandoif declare -F "$1" >/dev/null; then eval $1; fi
eval $(declare -F "$1")