On Tue, Aug 02, 2022 at 05:51:40PM +0200, Arno wrote:
Am 02.08.22 um 07:15 schrieb tomas@tuxteam.de:
On Mon, Aug 01, 2022 at 05:17:25PM +0200, Arno wrote:
Beim booten läuft bei mir ein script. Gestartet aus einem rc5.d/Sxx. [...] Soweit so normal.
[...]
Das ist alles halb so wild. Shell ist shell. Du musst wissen, mit welcher Du es zu tun hast (ist es die bash? ist es ihre kleine Schwester) und
Ja, es ist nur die /bin/sh
"die" /bin/sh gibt es nicht wirklich:
tomas@trotzki:~$ ls -al /bin/sh lrwxrwxrwx 1 root root 4 Dec 10 2020 /bin/sh -> dash
(Wenn Du sagst, dass es bei Dir eine Busybox ist, dann wird's etwas anders sein).
das einzige, was dieser Tage erwartet wird ist, dass sie einigermassen Bourne-kompatibel ist.
Du musst berücksichtigen, mit welcher Umgebung Du es zu tun hast (ist $PATH so wie Du sie erwartest? [...]
Das ist klar, da verwende ich nur absolute Pfade.
Nicht so klar: vielleicht willst Du Deinen Anwender*innen einen "Platz" geben für "hier was auch immer Ihr für rm benutzt". Die OO-Fuzzis nennen sowas "mixin". Man kann den Kopf so oder auch so drehen :-)
Zusatzfrage: Wenn ein Script wie meines gerade aus Funktionen besteht: Am Ende der Funktionsdefinitionen werden die aufgerufen. Kann man z.B. zum Testen, diese Funktionen (aus einer echten) Shell auch einzeln aufrufen?
How do the masters do it?
Einen netten Ansatz findest Du bei den alten sysvinit-Skripten. Die ersten zwei Zeilen (abgesehen von Kommentaren) in einem (Quizfrage: welches?) von meinen sehen so aus:
[ -r /usr/share/postgresql-common/init.d-functions ] || exit 0 . /usr/share/postgresql-common/init.d-functions
Es wird eine Datei "gesourct", in der irgendwelche nützliche Funktionen definiert werden. Das würde ich mal das "library"-Pattern nennen.
Konkret: Wenn value=10 vor dem Aufruf von init.d-functions steht, dann ist value dort bekannt. Aber was wenn ich in init.d-functions value2=20 setze. Kann ich die 20 in dem aufrufenden Vater-Script verwenden?
Nicht in einem "Unterskript". Aber in einer Funktion. Die Frage ist, ob Du das /willst/. Du siehst Deinem Hauptskript nicht an, ob eine Variable zwei Stockwerke tiefer verändert wird. Vielleicht passiert das nur aus Versehen, weil jemand "da unten" auch den Namen $BLUNTSCHLI für was ganz anderes verwendet wurde?
Entweder machst Du dazu also Gebrauch vom Library-Pattern (s.o.), oder Du "gibst ein Ergebnis zurück". Da strenggenommen Shell-Funktionen nur eine Art (Integer) "Fehlercode" zurückliefern, kannst Du mit stdout arbeiten:
secret-name () { echo "rumpelstilzchen" }
SECRET=$(secret-name)
... so etwas funktioniert. Auch noch krasser:
SECRET=$(secret-name | sed -e s/u/ü/g)
Das schöne an dem Stil ist, dass Du in Deinem Hauptprogramm /siehst/, dass der Wert der Variable SECRET verändert wird.
[...]
Nehmen wir an, ich habe ein Skript, nennen wir es "muuh":
#!/bin/bash echo "Guten Morgen"
say-hello () { echo hello }
say-good-bye () { echo good bye }
Und dann "source" ich das Ding in einem anderen:
... . muuh ...
Ok aber kann ich auch (Syntax frei erfunden) . muh::say-hello() machen und dann wird nur "hello" zurückgebeben. Das meine ich, wenn ich die Funktionen eines Scripts testen will.
Nö, sowas wie namespaces gibt es nicht.
Bei mir wäre gegenwärtig das Problem das das muh wohl so aussieht:
#/bin/sh funk1() { echo 1 } funk2() { echo 2 } funk3() { echo 3 } echo Test funk1 echo blabla funk3 funk2
Ich müsste zum Test die unteren 5 Zeilen komplett rausnehmen und source muh.sh funk2
machen um nur funk2 zu testen, richtig?
(Syntax-Anmerkung: nach "echo 1" usw muss wahrscheinlich ein ; sein)
Richtig. Der erste Stück geht in eine eigene Datei, my-functions, der zweite benutzt das. Das ist vermutlich die "lesbarste" Variante. Nicht die einzige. Eine andere:
#!/bin/sh # datei: muh fun1 () { ... } ... if [ -n "$TESTING" ] ; then exit 0 ; fi
echo blabla
Also: wenn die Variable TESTING gesetzt ist, dann hüpfst Du raus, nachdem die Funktionen definiert wurden aber bevor der Schaden angerichtet ist. Mir gefällt die Variante nicht so sehr, aber sie soll ja Dir gefallen :-)
Was passiert ist, dass wenn die Ausführung in meinem Skript an diesen Punkt kommt, "Guten Morgen" ausgegeben wird (wohin immer gerade stdout zeigt) und die zwei Funktionen definiert werden, die ich dann im weiteren Verlauf verwenden kann.
Immerhin. Also sind die Funktionen auch nach Ausführung noch verfügbar.
Ja, im Skript immer.
Ein ganz gerader, naiver Interpreter: mach' dies, dann mach' das [...]
Also vielen Dank für die Mühe, dann werd ich mich mal ans refactoring machen und mit kleinen Demos beginnen.
Gerne :)
lg