Przekazywanie deklaracji funkcji w skrypcie Bash lub Shell?

96

Czy jest coś takiego bashlub przynajmniej coś podobnego (obejścia), jak deklaracje forward, dobrze znane na przykład w C / C ++?

Czy jest coś takiego, bo na przykład zawsze jest to wykonywane w jednym przebiegu (wiersz po wierszu)?

Jeśli nie ma deklaracji forward, co powinienem zrobić, aby mój skrypt był bardziej czytelny. Jest dość długi i te definicje funkcji na początku, zmieszane ze zmiennymi globalnymi, sprawiają, że mój skrypt wygląda brzydko i jest trudny do odczytania / zrozumienia)? Proszę o zapoznanie się z dobrze znanymi / najlepszymi praktykami w takich przypadkach.


Na przykład:

# something like forward declaration
function func

# execution of the function
func

# definition of func
function func
{
    echo 123
}
Kiril Kirov
źródło

Odpowiedzi:

191

Świetne pytanie. Używam takiego wzorca dla większości moich skryptów:

#!/bin/bash

main() {
    foo
    bar
    baz
}

foo() {
}

bar() {
}

baz() {
}

main "$@"

Możesz czytać kod od góry do dołu, ale w rzeczywistości nie rozpoczyna się on aż do ostatniej linii. Przekazując "$@"do main () można uzyskać dostęp do argumentów wiersza polecenia $1, $2i inni, tak jak zwykle.

John Kugelman
źródło
3
Cześć, jak uporządkujesz dane, które mają być udostępniane między foo / bar / baz w twoim przykładzie? Zwykle po prostu umieszczam to na początku scenariusza. Czy tak jest nadal w przypadku korzystania z funkcji? A może lepiej jest umieścić dane globalne w main, a następnie przekazać je do foo / bar / baz jako argumenty? Jaka jest najlepsza praktyka?
bodacydo
4
Wolę argumenty. Poza tym ustawię zmienne globalne mainw funkcji lub bezpośrednio po niej main(np. setupLub parseArguments). Unikam ustawiania zmiennych globalnych powyżej main- kod nie powinien wychodzić poza main.
John Kugelman
Wydaje się to nieco analogiczne do tego, co if _ _ name _ _ == "_ _ main _ _": main()dzieje się w Pythonie
Sergiy Kolodyazhnyy
Jest to również fantastyczne, gdy używasz narzędzi takich jak Bats do testowania skryptów, rozbicie wszystkiego na funkcje znacznie ułatwia testowanie poszczególnych komponentów. Zobacz także wpis na blogu
dragon788
31

Kiedy moje skrypty bash za bardzo się rozrastają, używam mechanizmu dołączania:

Plik allMyFunctions:

foo() {
}

bar() {
}

baz() {
}

Plik main:

#!/bin/bash

. allMyfunctions

foo
bar
baz
mouviciel
źródło
28
Osobiście, gdy skrypt powłoki zaczyna przekraczać jeden plik, mam tendencję do przełączania się na inny język ;-)
Joachim Sauer
Czy nie byłoby lepiej użyć source allMyfunctions?
pydoge
4
@pydoge: sourcenie jest zgodny z POSIX. bashdefiniuje sourcejako alias do .: są funkcjonalnie równoważne.
mouviciel