2011-12-08 17 views
21

¿Es posible crear algo análogo a una función anónima cuyo valor se puede asignar a un elemento de matriz y luego llamar? Parece que no puedo encontrar una manera de hacer esto en un script de bash, pero tal vez haya una solución.Funciones anónimas en scripts de shell

Respuesta

47

Respuesta corta: No.

Respuesta larga: Nooooooooooooo.

Respuesta completa: Las funciones en bash no son objetos de primera clase, por lo tanto no puede haber una función anónima en bash.

+5

Como solución, definiría las funciones con nombres y almacenaría solo los nombres en la matriz; luego, simplemente evalúa el elemento de la matriz cuando quieras llamar a la función. – choroba

+1

@choroba Quizás debería publicar esto como una respuesta. Aunque no es directamente posible como describió Ignacio, su solución es una buena idea. – Matty

+0

¿El error bash en CVE-2014-6271 [link] (https://www.reddit.com/r/netsec/comments/2hbxtc/cve20146271_remote_code_execution_through_bash/ckrhvtl) confirma que las funciones anónimas pueden existir en scripts de shell? – Lizz

5

La técnica común es asignar definiciones de función condicional:

 
#!/bin/sh 

case $1 in 
a) foo() { echo case a; };; 
b) foo() { echo case b; };; 
*) foo() { echo default; } ;; 
esac 

foo 
8

Si realmente necesita matriz para almacenar las funciones, se pueden definir funciones con nombre y almacenar sólo sus nombres. A continuación, puede llamar a la función como ${array[n]}. O bien, puede nombrarlos func1 .. funcN y luego simplemente llame al func$n.

7

Es posible; Escribí una biblioteca para hacer exactamente esto, aunque es un proyecto muy extraño. El código fuente está disponible en http://github.com/spencertipping/bash-lambda. El uso de esta biblioteca:

$ my_array=() 
$ my_array[0]=$(fn x 'echo $((x + 1))') 
$ my_array[1]=$(fn x 'echo $((x + 2))') 
$ ${my_array[0]} 5 
6 
$ ${my_array[1]} 5 
7 
$ 

El truco es tener la función fn crear un archivo que contiene el cuerpo de la función, chmod +x ese archivo, y luego volver a su nombre. Esto hace que los archivos perdidos se acumulen, por lo que la biblioteca también implementa un recolector de elementos no utilizados asincrónico.

+0

¿Hay alguna manera de esperar que un comando termine de ejecutarse antes de ejecutar la función anónima? – William

0

Crear el archivo fn en su PATH

#!/bin/sh 

printusage() { 
     printf "Create anonymous function, for example\n" 
     printf "fn 'echo "$1 $2"'" 
     exit 1 
} 


[ "$#" = "1" ] || printusage 
fun=$1 
[ "$fun" = "" ] && printusage 
fun_file="$(mktemp /tmp/fun_XXXXXX)" 

echo "#!/bin/sh" > "$fun_file" 
echo "" >> "$fun_file" 
echo "$fun" >> "$fun_file" 
chmod u+x "$fun_file" 

echo "$fun_file" 

A continuación, puede hacer:

foo=$(fn 'echo $1') 
${foo} "bar" 
0

fiesta así es Turing completo, soo, eso es perfectamente posible;)

pero aparte de esto realmente no vale la pena la consideración.

se podía simular este tipo de comportamiento, aunque con algo a lo largo de esta línea:

echo myval ; (foocmd "$_" && barcmd "$_") 

pero ¿por qué?!?

Cuestiones relacionadas