2011-12-08 19 views
21

È possibile creare qualcosa di analogo a una funzione anonima il cui valore può essere assegnato a un elemento di matrice e successivamente chiamato? Non riesco a trovare un modo per farlo in uno script bash, ma forse c'è una soluzione alternativa.Funzioni anonime negli script di shell

risposta

47

Risposta breve: No.

Risposta lunga: Nooooooooooooo.

Risposta completa: le funzioni in bash non sono oggetti di prima classe, quindi non è possibile avere funzioni anonime in bash.

+5

Per risolvere il problema, definirei le funzioni con i nomi e memorizzerò solo i nomi nell'array; quindi basta "evalare" l'elemento dell'array quando si desidera chiamare la funzione. – choroba

+1

@choroba Forse dovresti postare questo come risposta. Anche se non è direttamente possibile come descritto da Ignacio, la tua soluzione è una buona idea. – Matty

+0

Il bug di bash in CVE-2014-6271 [collegamento] (https://www.reddit.com/r/netsec/comments/2hbxtc/cve20146271_remote_code_execution_through_bash/ckrhvtl) conferma che le funzioni anonime possono esistere negli script di shell? – Lizz

5

La tecnica comune è quello di assegnare le definizioni di funzione condizionale:

 
#!/bin/sh 

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

foo 
8

Se avete veramente bisogno array per memorizzare le funzioni, è possibile definire funzioni con nome e memorizzare solo i loro nomi. È quindi possibile chiamare la funzione come ${array[n]}. Oppure, è possibile denominarli func1 .. funcN e quindi chiamare semplicemente func$n.

7

È possibile; Ho scritto una biblioteca per fare esattamente questo, anche se è un progetto molto strano. Il codice sorgente è disponibile allo http://github.com/spencertipping/bash-lambda. Usando questa libreria:

$ 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 
$ 

Il trucco è quello di avere la funzione fn creare un file contenente il corpo della funzione, chmod +x quel file, per poi tornare il suo nome. Ciò causa l'accumulo di file vaganti, motivo per cui la libreria implementa anche un garbage collector asincrono di mark/sweep.

+0

C'è un modo per aspettare che un comando finisca di essere eseguito prima di eseguire la funzione anonima? – William

0

Creare il file fn nel 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" 

È quindi possibile fare:

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

ben bash è Turing completa, thats soo perfettamente possibile;)

ma a parte questo non ne vale veramente la pena.

si potrebbe simulare tale comportamento anche se con qualcosa seguendo questa linea:

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

ma perché?!?