Muszę przekazać funkcję jako parametr w Bash. Na przykład następujący kod:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
Powinien wynik:
before
Hello world
after
Wiem, że eval
nie jest poprawne w tym kontekście, ale to tylko przykład :)
Dowolny pomysł?
function
słowo, nie możesz uzyskać dostępu do tych wewnętrznych metod, dopóki nie uruchomisz metody najwyższego poziomu.Myślę, że nikt nie odpowiedział na to pytanie. Nie zapytał, czy mógłby powtórzyć kolejno struny. Raczej autor pytania chce wiedzieć, czy może symulować zachowanie wskaźnika funkcji.
Jest kilka odpowiedzi, które są bardzo podobne do tego, co bym zrobił, i chcę je rozszerzyć o inny przykład.
Od autora:
function x() { echo "Hello world" } function around() { echo "before" ($1) <------ Only change echo "after" } around x
Aby to rozwinąć, będziemy mieć funkcję x echo „Witaj świecie: $ 1”, która będzie pokazywać, kiedy naprawdę następuje wykonanie funkcji. Przekażemy ciąg będący nazwą funkcji „x”:
function x() { echo "Hello world:$1" } function around() { echo "before" ($1 HERE) <------ Only change echo "after" } around x
Aby to opisać, ciąg „x” jest przekazywany do funkcji around (), która wywołuje echo „przed”, wywołuje funkcję x (poprzez zmienną $ 1, pierwszy parametr przekazany dookoła), przekazując argument „TUTAJ”, a na końcu odbija się echem po .
Poza tym jest to metodologia używania zmiennych jako nazw funkcji. W rzeczywistości zmienne zawierają łańcuch będący nazwą funkcji i ($ zmienna arg1 arg2 ...) wywołuje funkcję przekazującą argumenty. Zobacz poniżej:
function x(){ echo $3 $1 $2 <== just rearrange the order of passed params } Z="x" # or just Z=x ($Z 10 20 30)
daje: 30 10 20, gdzie wykonaliśmy funkcję o nazwie "x" przechowywaną w zmiennej Z i przekazaliśmy parametry 10 20 i 30.
Powyżej, w którym odwołujemy się do funkcji, przypisując im nazwy zmiennych, abyśmy mogli użyć zmiennej zamiast znajomości nazwy funkcji (co jest podobne do tego, co można zrobić w bardzo klasycznej sytuacji wskaźnika funkcji w c w celu uogólnienia przepływu programu, ale przed -wybierając wywołania funkcji, które będziesz wykonywać na podstawie argumentów wiersza poleceń).
W bashu nie są to wskaźniki funkcji, ale zmienne, które odnoszą się do nazw funkcji, których później użyjesz.
źródło
()
to nie rozpocznie podpowłoki?nie ma potrzeby używania
eval
function x() { echo "Hello world" } function around() { echo "before" var=$($1) echo "after $var" } around x
źródło
Nie możesz przekazać niczego do funkcji innej niż ciągi znaków. Zastępowanie procesów może w pewnym sensie to udawać. Bash ma tendencję do przytrzymywania otwartego FIFO do czasu zakończenia jego rozwinięcia.
Oto szybki, głupiutki
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)
Funkcje można eksportować, ale nie jest to tak interesujące, jak się początkowo wydaje. Uważam, że jest to przydatne głównie do udostępniania funkcji debugowania skryptom lub innym programom, które uruchamiają skrypty.
( id() { "$@" } export -f id exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi' )
id
nadal pobiera tylko ciąg, który jest nazwą funkcji (automatycznie importowany z serializacji w środowisku) i jej argumenty.Komentarz Pumba80 do innej odpowiedzi jest również dobry (
eval $(declare -F "$1")
), ale jest przydatny głównie w przypadku tablic, a nie funkcji, ponieważ są one zawsze globalne. Gdybyś miał to uruchomić w ramach funkcji, wszystko, co zrobiłby, to przedefiniowanie jej, więc nie ma żadnego efektu. Nie można go używać do tworzenia domknięć, funkcji częściowych lub „instancji funkcji” zależnych od tego, co jest związane w bieżącym zakresie. W najlepszym przypadku można to wykorzystać do przechowywania definicji funkcji w łańcuchu, który zostanie przedefiniowany w innym miejscu - ale te funkcje również mogą być zakodowane na stałe, chyba że oczywiścieeval
są używaneZasadniczo Bash nie może być używany w ten sposób.
źródło
Lepszym podejściem jest użycie zmiennych lokalnych w funkcjach. Problem polega zatem na tym, jak przekazać wynik dzwoniącemu. Jednym z mechanizmów jest użycie zastępowania poleceń:
function myfunc() { local myresult='some value' echo "$myresult" } result=$(myfunc) # or result=`myfunc` echo $result
Tutaj wynik jest wyprowadzany na standardowe wyjście, a obiekt wywołujący używa podstawiania poleceń, aby przechwycić wartość w zmiennej. Zmiennej można następnie użyć w razie potrzeby.
źródło
Powinieneś mieć coś w stylu:
function around() { echo 'before'; echo `$1`; echo 'after'; }
Możesz wtedy zadzwonić
around x
źródło
eval jest prawdopodobnie jedynym sposobem, aby to osiągnąć. Jedynym prawdziwym minusem jest aspekt bezpieczeństwa, ponieważ musisz się upewnić, że nic złośliwego nie zostanie przekazane i zostaną wywołane tylko funkcje, które chcesz, aby zostały wywołane (wraz z sprawdzeniem, czy nie ma nieprzyjemnych znaków, takich jak ';') w nim również).
Więc jeśli to ty wywołujesz kod, eval jest prawdopodobnie jedynym sposobem, aby to zrobić. Zauważ, że istnieją inne formy ewaluacji, które prawdopodobnie działałyby również z wykorzystaniem podpoleceń ($ () i ``), ale nie są one bezpieczniejsze i są droższe.
źródło
eval $1
wywołałby funkcję za pomocąif declare -F "$1" >/dev/null; then eval $1; fi
eval $(declare -F "$1")