funkcja wywołania zadeklarowana poniżej

15

Czy można wywołać funkcję zadeklarowaną poniżej w bash?

Przykład

if [ "$input" = "yes" ]; then
    YES_FUNCTION
elif [ "$input" = "no" ]; then
    NO_FUNCTION
else
    exit 0;
fi

YES_FUNCTION()
{
  .....
  .....
}

NO_FUNCTION()
{
  .....
  .....
}
msp9011
źródło

Odpowiedzi:

37

Jak powiedzieli inni, nie możesz tego zrobić.

Ale jeśli chcesz ułożyć kod w jeden plik, tak aby główny program znajdował się na górze pliku, a inne funkcje są zdefiniowane poniżej, możesz to zrobić, mając oddzielną mainfunkcję.

Na przykład

#!/bin/sh

main() {
    if [ "$1" = yes ]; then
        do_task_this
    else
        do_task_that
    fi
}

do_task_this() {
    ...
} 
do_task_that() {
    ...
} 

main "$@"; exit

Kiedy wywołujemy mainna końcu pliku, wszystkie funkcje są już zdefiniowane. Wyraźnie przechodząc "$@"do mainjest wymagane, aby argumenty wiersza poleceń skryptu widocznego w funkcji.

Jawne exitw tym samym wierszu co wywołanie main nie jest obowiązkowe, ale można go użyć, aby zapobiec pomyłce działającego skryptu, jeśli plik skryptu zostanie zmodyfikowany. Bez tego powłoka po mainpowrocie próbowałaby czytać polecenia ze skryptu . (zobacz Jak odczytać cały skrypt powłoki przed jego uruchomieniem? )

ilkkachu
źródło
@ikkachu sądzę, że powinno działać .. pozwól mi sprawdzić.
msp9011
8
W skryptach Bash często [[ ${BASH_SOURCE[0]} = "$0" ]] && Main "$@"wywołuję funkcję główną, dzięki czemu mogę ją pobrać w innym skrypcie bez Mainwykonywania. Następnie mogę ponownie użyć funkcji lub napisać testy, aby je sprawdzić.
BlackJack
11
Posiadanie main "$@"; exit(z exittą samą linią co main) jest również przydatne jako zabezpieczenie przed modyfikacją pliku podczas jego interpretacji.
Stéphane Chazelas
2
@JoL, to, co jest czytane, nie jest ponownie czytane, a powłoka będzie musiała przeczytać i przeanalizować cały tekst pętli przed rozpoczęciem jej uruchamiania, ale po powrocie pętli będzie kontynuować czytanie z pozostałej części pliku w aktualna pozycja (a jeśli plik został zmodyfikowany, to wszystko psuje). Jeśli wszystko jest w funkcjach, powłoka musi wszystko przeczytać, zanim zacznie cokolwiek robić (z wyjątkiem definiowania tych funkcji), jeśli umieścimy exitten sam wiersz, ponieważ mainupewniamy się, że powłoka nie odczyta niczego z pliku po mainpowrocie.
Stéphane Chazelas
1
@MontyHarder, nie ma znaczenia, czy używasz main; exit, main; exit $?lub main <EOF>, we wszystkich przypadkach, kod zakończenia mainjest używany jako kod wyjścia skryptu. exitByłoby po prostu rzeczy, aby zapobiec coraz zawiedli jeśli ktoś edytuje skrypt przy włączonym silniku.
ilkkachu
13

Nie, funkcje muszą istnieć w środowisku powłok w momencie ich wywoływania.

„Przewodnik po stylu Shell” firmy Google ma poprawkę:

Wywołana funkcja mainjest wymagana dla skryptów wystarczająco długich, aby zawierały co najmniej jedną inną funkcję.

Na samym końcu skryptu, po wszystkich funkcjach, jako jedyna instrukcja, której nie ma w funkcji, miałbyś

main "$@"

Wywołałoby to mainfunkcję z dowolnymi parametrami podanymi przez skrypt. mainFunkcja może być umieszczony w górnej części skryptu (przewodnik styl mówi, aby umieścić go na dole, ale potem znowu, to mówi wiele rzeczy).

Gdy powłoka dotrze do mainwywołania, wszystkie funkcje w skrypcie zostały przeanalizowane i dlatego można je wywoływać z mainfunkcji.

Kusalananda
źródło
9

Nie, funkcje muszą zostać zadeklarowane przed ich użyciem. Skrypty powłoki są odczytywane wiersz po wierszu i uruchamiane wiersz po wierszu; więc funkcja nie istnieje, dopóki jej deklaracja nie zostanie wykonana.

Stephen Kitt
źródło
masz rację. problem polega na tym, że mam ponad 30 funkcji w skrypcie. jest to dość trudne, gdy czytamy kod. W Cwygodnym miejscu.
msp9011
3
Możesz umieścić swoje deklaracje funkcji w innym pliku i źródło ( . yourfile).
Stephen Kitt,
Tak, próbowałem tego, ale wymagany jest jeden skrypt.
msp9011
@SivaPrasath Jaki jest dokładnie problem? Po prostu zdefiniuj wszystkie funkcje, może nawet wstawiając główny kod do funkcji, a następnie ostatni wiersz pokazuje, która funkcja jest wywoływana i zawiera główną część skryptu.
BlackJack
@SivaPrasath W C nie ma nagich ifinstrukcji poza funkcją. Funkcja nie musi być definiowana, kiedy deklarujesz funkcję ifzawierającą, tylko kiedy ją wywołujesz .
chepner
4

Powłoka nie ma pojęcia o declaringfunkcji. Więc nie możesz mieć deklaracji przekazania.

W konsekwencji musisz mieć implementację funkcji odczytaną przez powłokę, zanim będzie można ją wywołać.

schily
źródło
4
Technicznie niektóre powłoki (ksh, zsh) mają funkcję automatycznego ładowania, która może być postrzegana jako forma deklaracji (gdzie autoload fdeklaruje funkcję, ale jej ciało jest ładowane tylko przy pierwszym wywołaniu). Nie dotyczy to jednak PO bash.
Stéphane Chazelas