Aufruffunktion unten deklariert

15

Kann man eine Funktion aufrufen, die in bash deklariert ist?

Beispiel

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

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

NO_FUNCTION()
{
  .....
  .....
}
msp9011
quelle

Antworten:

35

Wie andere gesagt haben, kann man das nicht tun.

Wenn Sie den Code jedoch so in einer Datei anordnen möchten, dass sich das Hauptprogramm oben in der Datei befindet und andere Funktionen unten definiert sind, können Sie dies mit einer separaten mainFunktion tun .

Z.B

#!/bin/sh

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

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

main "$@"; exit

Wenn wir mainam Ende der Datei aufrufen , sind alle Funktionen bereits definiert. Die explizite Übergabe "$@"an mainist erforderlich, um die Befehlszeilenargumente des Skripts in der Funktion sichtbar zu machen.

Der explizite Eintrag exitin derselben Zeile wie der Aufruf von main ist nicht obligatorisch, kann jedoch verwendet werden, um zu verhindern, dass ein ausgeführtes Skript durcheinander gebracht wird, wenn die Skriptdatei geändert wird. Ohne dies würde die Shell versuchen, nach der mainRückkehr weitere Befehle aus der Skriptdatei zu lesen . (Siehe Wie lese ich das gesamte Shell-Skript, bevor ich es ausführe? )

ilkkachu
quelle
@ikkachu denke, es sollte funktionieren .. lassen Sie mich überprüfen.
msp9011
7
Bei Bash-Skripten benutze ich oft [[ ${BASH_SOURCE[0]} = "$0" ]] && Main "$@", um die Hauptfunktion aufzurufen, damit ich sie in einem anderen Skript verwenden kann, ohne Mainsie auszuführen. Dann kann ich die Funktionen wiederverwenden oder Tests schreiben, um sie zu überprüfen.
Blackjack
11
Mit main "$@"; exit(mit exitauf der gleichen Linie wie main) ist auch als ein Schutz gegen die Datei geändert wird , während es interpretiert wird.
Stéphane Chazelas
2
@JoL, was gelesen wird, wird nicht erneut gelesen, und die Shell muss den gesamten Text einer Schleife lesen und analysieren, bevor sie ausgeführt wird. Nachdem die Schleife zurückkehrt, liest sie weiter aus dem Rest der Datei unter die aktuelle Position (und wenn die Datei geändert wurde, wird es Dinge vermasseln). Wenn sich alles in Funktionen befindet, muss die Shell alles lesen, bevor sie etwas unternimmt (mit Ausnahme der Definition dieser Funktionen). Wenn Sie das exitin dieselbe Zeile setzen main, stellen Sie sicher, dass die Shell nach der mainRückgabe nichts mehr aus der Datei liest .
Stéphane Chazelas
1
@MontyHarder, es spielt keine Rolle, ob Sie verwenden main; exit, main; exit $?oder main <EOF>in allen Fällen wird der Exit-Code von mainals Exit-Code des Skripts verwendet. Das exitwäre nur, um zu verhindern, dass Dinge durcheinander geraten, wenn jemand das Skript bearbeitet, während es läuft.
Ilkkachu
13

Nein, die Funktionen müssen zum Zeitpunkt des Aufrufs in der Shell-Umgebung vorhanden sein.

Googles "Shell Style Guide" hat eine Lösung für dieses Problem:

Eine aufgerufene Funktion mainist erforderlich, damit Skripte mindestens eine weitere Funktion enthalten.

Ganz am Ende des Skripts, nachdem alle Funktionen, als einzige Anweisung nicht in einer Funktion, hätten Sie

main "$@"

Dies würde die mainFunktion mit allen Parametern aufrufen, die dem Skript gegeben wurden. Die mainFunktion könnte sich am oberen Rand des Skripts befinden (der Styleguide sagt, dass sie am unteren Rand stehen soll, aber andererseits sagt sie viele Dinge).

Wenn die Shell zum mainAufruf gelangt, wurden alle Funktionen im Skript analysiert und können daher innerhalb der mainFunktion aufgerufen werden.

Kusalananda
quelle
9

Nein, Funktionen müssen deklariert werden, bevor sie verwendet werden. Shell-Skripte werden Zeile für Zeile gelesen und Zeile für Zeile ausgeführt. Eine Funktion existiert also erst, wenn ihre Deklaration ausgeführt wurde.

Stephen Kitt
quelle
Du hast recht. Das Problem ist, ich habe mehr als 30 Funktionen in einem Skript. Es ist ziemlich schwierig, den Code zu lesen. In Ces ist bequem.
msp9011
3
Sie können Ihre Funktionsdeklarationen in einer anderen Datei ablegen und als Quelle angeben ( . yourfile).
Stephen Kitt
Ja, das habe ich versucht, aber die Voraussetzung ist, ein einziges Skript zu haben.
msp9011
@SivaPrasath Was genau ist das Problem? Definieren Sie einfach alle Funktionen, setzen Sie vielleicht sogar den Hauptcode in eine Funktion und die letzte Zeile zeigt, welche Funktion aufgerufen wird und enthält den Hauptteil des Skripts.
Blackjack
@SivaPrasath In C haben Sie keine nackten ifAnweisungen außerhalb einer Funktion. Die Funktion muss nicht definiert werden, wenn Sie die -containing-Funktion deklarierenif , sondern nur, wenn Sie sie aufrufen .
Chepner
4

Die Shell hat kein declaringFunktionskonzept. Sie können also keine Vorwärtsdeklaration haben.

Folglich muss die Funktionsimplementierung von der Shell gelesen werden, bevor sie aufgerufen werden kann.

schily
quelle
4
Technisch gesehen verfügen einige Shells (ksh, zsh) über eine Funktion zum automatischen Laden , die als eine Art Deklaration angesehen werden kann (wobei autoload fdie Funktion deklariert wird, ihr Body jedoch erst beim ersten Aufruf geladen wird). Dies gilt jedoch nicht für die OPs bash.
Stéphane Chazelas