2011-12-08 19 views
21

Czy można utworzyć coś analogicznego do anonimowej funkcji, której wartość można przypisać do elementu tablicy, a następnie wywołać? Nie mogę znaleźć sposobu, aby to zrobić w skrypcie basha, ale być może istnieje obejście.Funkcje anonimowe w skryptach powłoki

Odpowiedz

47

Krótka odpowiedź: Nie

Długa odpowiedź: Nooooooooooooo.

Pełna odpowiedź: Funkcje w bash nie są obiektami pierwszej klasy, dlatego nie może być czegoś takiego jak anonimowa funkcja w bashu.

+5

Jako obejście zdefiniowałem funkcje z nazwami i zapisałem tylko nazwy w tablicy; następnie po prostu 'eval' element tablicy, gdy chcesz wywołać funkcję. – choroba

+1

@choroba Być może powinieneś opublikować to jako odpowiedź. Chociaż nie jest to możliwe bezpośrednio, jak opisał Ignacio, twoje obejście jest dobrym pomysłem. – Matty

+0

Czy błąd bash w CVE-2014-6271 [link] (https://www.reddit.com/r/netsec/comments/2hbxtc/cve20146271_remote_code_execution_through_bash/ckrhvtl) potwierdza, że ​​anonimowe funkcje mogą istnieć w skryptach powłoki? – Lizz

5

Wspólne technika jest przypisanie definicji funkcji warunkowo:

 
#!/bin/sh 

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

foo 
8

Jeśli naprawdę potrzebujesz tablicę do przechowywania funkcji można zdefiniować nazwane funkcje i przechowywać tylko ich nazwy. Następnie możesz wywołać funkcję jako ${array[n]}. Lub możesz nazwać je func1 .. funcN, a następnie po prostu zadzwoń func$n.

7

Jest to możliwe; Napisałem bibliotekę, aby to dokładnie zrobić, chociaż jest to bardzo dziwny projekt. Kod źródłowy jest dostępny pod adresem http://github.com/spencertipping/bash-lambda. Korzystanie z tej biblioteki:

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

Sztuką jest mieć funkcja fn utworzyć plik zawierający ciało funkcji, chmod +x że plik, a następnie powrócić na swoją nazwę. Powoduje to gromadzenie się zbędnych plików, dlatego też biblioteka implementuje także asynchroniczny zbieracz znaczników/przemiatników.

+0

Czy istnieje sposób oczekiwania na wykonanie polecenia kończącego wykonywanie przed wykonaniem anonimowej funkcji? – William

0

Utwórz plik fn w 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" 

Można wtedy zrobić:

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

dobrze bash jest Turinga kompletne, soo ów całkiem możliwe;)

Ale oprócz tego nie jest to warte rozważenia.

można symulować takie zachowanie chociaż coś wzdłuż tej linii:

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

ale dlaczego?!?

Powiązane problemy