2011-04-15 28 views
49

Necesito pasar una función como parámetro en Bash. Por ejemplo, el siguiente código:Bash: pasar una función como parámetro

function x() { 
    echo "Hello world" 
} 

function around() { 
    echo "before" 
    eval $1 
    echo "after" 
} 

around x 

es la Salida:

before 
Hello world 
after 

eval no es correcto en ese contexto, pero eso es sólo un ejemplo :)

Alguna idea?

Respuesta

67

Si no es necesario ningún procedimiento especial, como el retraso de la evaluación del nombre de la función o de sus argumentos, que no es necesario eval:

function x()  { echo "Hello world";   } 
function around() { echo before; $1; echo after; } 

around x 

hace lo que quiere. Incluso puede pasar a la función y sus argumentos de esta manera:

function x()  { echo "x(): Passed $1 and $2"; } 
function around() { echo before; "[email protected]"; echo after; } 

around x 1st 2nd 

impresiones

before 
x(): Passed 1st and 2nd 
after 
0

eval es probablemente la única manera de lograrlo. La única desventaja real es el aspecto de seguridad, ya que es necesario asegurarse de que no se pase nada malicioso y de que solo se llamen las funciones a las que desea llamar (junto con verificar que no tenga caracteres desagradables como ';' en ella también).

Así que si usted es el que llama al código, entonces eval es probablemente la única forma de hacerlo. Tenga en cuenta que existen otras formas de evaluación que probablemente también funcionarán con los subcomandos ($() y ``), pero no son más seguros y son más caros.

+0

eval es la única manera de hacerlo. – Wes

+1

Puede verificar fácilmente si 'eval $ 1' llamaría a una función usando' if declare -F "$ 1">/dev/null; luego evalúa $ 1; fi' – user123444555621

+2

... o mejor aún: 'eval $ (declarar -F" $ 1 ")' – user123444555621

1

usted debe tener algo en la línea de:

function around() 
{ 
    echo 'before'; 
    echo `$1`; 
    echo 'after'; 
} 

A continuación, puede llamar around x

1

Un mejor enfoque es utilizar variables locales en sus funciones. El problema entonces es cómo obtienes el resultado para la persona que llama. Uno de los mecanismos es utilizar comando de sustitución:

function myfunc() 
{ 
    local myresult='some value' 
    echo "$myresult" 
} 

result=$(myfunc) # or result=`myfunc` 
echo $result 

Aquí, el resultado es la salida a la salida estándar y la persona que llama utiliza la sustitución de comandos para capturar el valor de una variable. La variable se puede usar según sea necesario.

13

no hay necesidad de usar eval

function x() { 
    echo "Hello world" 
} 

function around() { 
    echo "before" 
    var=$($1) 
    echo "after $var" 
} 

around x 
5

No puede pasar nada a una función distinta de cuerdas. Las sustituciones de procesos pueden falsificarlo. Bash tiende a mantener abierto el FIFO hasta que un comando se expande hasta completarse.

Aquí hay una rápida tonto uno

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 pueden ser exportados, pero esto no es tan interesante como parece a primera vista. Encuentro que es principalmente útil para que las funciones de depuración sean accesibles para los scripts u otros programas que ejecutan scripts.

(
    id() { 
     "[email protected]" 
    } 

    export -f id 
    exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi' 
) 

id todavía sólo para crear una cadena que pasa a ser el nombre de una función (importados automáticamente de una serialización en el medio ambiente) y sus argumentos.

El comentario de Pumbaa80 a otra respuesta también es bueno (eval $(declare -F "$1")), pero es principalmente útil para arreglos, no para funciones, ya que son siempre globales. Si tuviera que ejecutar esto dentro de una función, todo lo que haría sería redefinirlo, para que no haya ningún efecto. No se puede usar para crear cierres o funciones parciales o "instancias de función" que dependan de lo que suceda en el alcance 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 pueden codificarse a menos que se use eval

Básicamente Bash no se puede usar así.

9

No creo que nadie haya respondido la pregunta. Él no preguntó si podía hacer un eco de cadenas en orden. Más bien, el autor de la pregunta quiere saber si puede simular el comportamiento del puntero de la función.

Hay un par de respuestas que se parecen mucho a lo que haría, y quiero ampliarlo con otro ejemplo.

Del autor:

function x() { 
    echo "Hello world" 
} 

function around() { 
    echo "before" 
    ($1)     <------ Only change 
    echo "after" 
} 

around x 

Para ampliar esto, vamos a tener una función x echo "Hola mundo: $ 1" para mostrar cuando se produce realmente la ejecución de la función. Pasaremos una cadena que es el nombre de la función de "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 alrededor de() que ecos "antes", llama a la función x (a través de la variable $ 1, el primer parámetro pasó a su alrededor) pasando el argumento "AQUÍ", finalmente echos después.

Como otro lado, 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 que pasa los argumentos. Ver más 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 se ejecuta la función denominada "X" almacenado en la variable Z y pasan los parámetros 10 20 y 30.

Por encima de donde Referencia de funciones mediante la asignación de nombres de variables 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 de programa, pero preseleccionando las llamadas de función que realizará basado en argumentos de línea de comando).

En bash, estos no son punteros de función, sino variables que hacen referencia a los nombres de las funciones que utilizará más adelante.

+0

Esta respuesta es increíble. Hice bash scripts de todos los ejemplos y los ejecuté. También me gustó mucho cómo hiciste creadores de "solo cambio", lo que ayudó mucho. Su penúltimo párrafo tiene una ortografía incorrecta: "Aabove" –

+0

Typo corregido. Gracias @J MADISON – uDude

+0

¿por qué lo envuelves en '()' no comenzará eso un sub-shell? – horseyguy

Cuestiones relacionadas