ui
Anmeldungsdatum: 22. November 2008
Beiträge: 603
|
Ich als Anfänger finde es schwer und gefährlich Bash-Skripte zu schreiben. Habe gerade mit folgendem Skript aus Versehen mein Root-Verzeichnis gelöscht:
| #Vorsicht: Skript löscht Root-Verzeichnis !!!
#Leerzeichen links/rechts vom = ist ein ganz böser Fehler. Da $ZIEL dadurch leer bleibt und Z.5 so /* löscht
#statt /home/ui/haette/so/schoen/sein/koennen/*:
ZIEL = /home/ui/haette/so/schoen/sein/koennen;
rm -r $ZIEL/*;
|
Jetzt frage ich mich ob
es einen Präprozessor gibt, der die Schwächen der Bash-Syntax abfängt (vergleichbar TypeScript/JavaScript oder Sass/CSS) Python oder andere Skriptsprachen die sicherere Wahl sind
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
ui schrieb: Habe gerade mit folgendem Skript aus Versehen mein Root-Verzeichnis gelöscht:
Da war der grundsätzliche Fehler eher als root zu arbeiten, wenn man in einem Benutzerverzeichnis unterwegs ist... - der Beste Schutz gegen unerwünschte Löschungen ist das mit den minimal nötigen Rechten zu machen. Jetzt frage ich mich ob
Wie genau soll das funktionieren? Wenn musst du da selber Checks einbauen, um zu prüfen, ob deine Variablen leer bzw. undefiniert sind - z.B.:
| [ -n "$ZIEL" ] && {echo "ZIEL ist leer!" && exit 1;}
|
TypeScript hilft dir nur dabei Syntax- und Fehler bei den verwendeten Typen zu finden, aber Bugs aus der Kategorie "mein semantisch korrekter Code tut nicht das, was ich von ihm erwarte" kann es auch nicht abfangen.
Ansonsten hilft es Skripte in einer Testumgebung (z.B. Docker-Container) und ggf. mit Debug-Ausgaben (vgl. http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html) auszuführen, um zu sehen, ob sie wie gewünscht arbeiten. Wenn es darum geht Fehler zu werfen, wenn unerwartete Daten kommen möglicherweise - aber auch da sollte man nach Möglichkeit auf die Fehlerfälle testen, die man erwartet, weil nicht alles automatisch abgefangen wird, was zwar im Programm steht aber vom Nutzer nicht gewollt ist. Python3 macht insbesondere in Verbindung mit der pathlib in viele Fällen deutlich mehr Spaß als Shell-Skripte (z.B. muss man sich kaum Gedanken ums richtige Quoting machen und nicht mit null-Terminierten Strings arbeiten, um Dateinamen mit Newlines richtig zu behandeln), dafür schreibt man mehr Code. Wenn man will, kann man mit Projekten wie mypy dann auch noch Type-Checking realisieren. | #!/usr/bin/env python3
from pathlib import Path
import shutil
ZIEL = pathlib.Path('/home/ui/haette/so/schoen/sein/koennen')
for p in ZIEL.glob('*'):
if p.is_dir():
shutil.rmtree(p) # https://docs.python.org/3/library/shutil.html#shutil.rmtree
else:
p.unlink()
|
|
Cranvil
Anmeldungsdatum: 9. März 2019
Beiträge: 990
|
Wie bereits geschrieben, kannst du Skripte in verschieden stark abgeschirmten Testumgebungen ausprobieren und natürlich nur auf der Berechtigungsstufe, die unbedingt notwendig ist. Zusätzlich gibt es ShellCheck, mit dem sich die gröbsten Schnitzer finden lassen - wie beispielsweise die überzähligen Leerzeichen in deiner Variablenzuweisung. Damit sollten sich einige Fehler finden und korrigieren lassen, wobei es keine Garantie gibt, dass du nicht doch versehentlich einen Weg findest, dir syntaktisch korrekt das System unter den Füßen wegzureißen (oder schlimmer: alle Daten).
|
ui
(Themenstarter)
Anmeldungsdatum: 22. November 2008
Beiträge: 603
|
Gibt es zu Python eine Alternative mit einer Syntax ähnlich der Programmiersprache C? JavaScript z.B.? Selbst wenn diese Alternative nicht so mächtig ist wie Python.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Java Script hat mit C bis auf geschweifte Klammern und ein Semicolon am Zeilenende eigentlich kaum Gemeinsamkeiten... - aber ja, prinzipiell kannst du z.B. mit Node.js CLI-Skripte erstellen - ob man das will ist eine andere Frage.
|
ui
(Themenstarter)
Anmeldungsdatum: 22. November 2008
Beiträge: 603
|
Ich bin mir auch nicht sicher. Vermutlich ist Python die bessere Wahl. Aber ich werde nicht warm mit der Python Syntax. Finde die C-Syntax so toll. Gerade die geschweiften Klammern. Aber ich danke Dir und allen anderen für den tollen Rundumblick!
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Ja, benutze shellcheck: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | shellcheck delete_all.xh
In delete_all.xh line 1:
#Vorsicht: Skript löscht Root-Verzeichnis !!!
^-- SC2148: Tips depend on target shell and yours is unknown. Add a shebang.
In delete_all.xh line 4:
ZIEL = /home/ui/haette/so/schoen/sein/koennen;
^-- SC1068: Don't put spaces around the = in assignments.
In delete_all.xh line 5:
rm -r $ZIEL/*;
^-- SC2115: Use "${var:?}" to ensure this never expands to /* .
|
Viel mehr kann man wohl kaum erwarten.
|
Cranvil
Anmeldungsdatum: 9. März 2019
Beiträge: 990
|
Da bereits nach Skriptsprachen mit C-ähnlicher Syntax gefragt wurde (PHP oder Perl vielleicht? 😉 ), gehe ich davon aus, dass in dem Bereich Kenntnisse vorliegen und deshalb schnell mal solche Fehler gemacht werden. Ging mir am Anfang auch öfter so, da ich Programmieren zuerst mit Java gelernt habe, das sich auch nicht so sehr darum kümmert, wie viele Leerzeichen man um den Zuweisungsoperator setzt.
|
ui
(Themenstarter)
Anmeldungsdatum: 22. November 2008
Beiträge: 603
|
Shellcheck werde ich zukünftig benutzen. Dessen vorgeschlagene Abwandlung ${ZIEL:?}/* kannte ich nicht. Bricht das Skript an dieser Stelle ab falls ZIEL leer ist.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
ui schrieb: Dessen vorgeschlagene Abwandlung ${ZIEL:?}/* kannte ich nicht. Bricht das Skript an dieser Stelle ab falls ZIEL leer ist.
Ja, das ist eine Parameter Expansion, die abbricht, wenn Ziel nicht definiert ist oder ein leerer String ist - siehe auch https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html: ${parameter:?word} If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is substituted.
|
ui
(Themenstarter)
Anmeldungsdatum: 22. November 2008
Beiträge: 603
|
Schade nur, dass so etwas mit der Parameter Expansion nicht geht: 1
2
3
4
5
6
7
8
9
10
11
12
13
14 | #!/bin/bash
#Fehlerhafte Zuweisung:
VAR = Variableninhalt
mailAdmin(){
<E-Mail an Admin>
}
if echo ${VAR:?mailAdmin} ; then
<...>
fi
exit 0
|
|
Cranvil
Anmeldungsdatum: 9. März 2019
Beiträge: 990
|
Du könntest schauen, ob du was mit den anderen beschriebenen Expansionen anfangen kannst oder dich mit der manpage von test 🇬🇧 beschäftigen
Dieses kleine Kommandozeilenprogramm ist auch unter dem Namen [ bekannt und gibt einige Möglichkeiten, sich programmatisch einen Überblick über bestimmte Bedingungen zu verschaffen. Die Bash hat viel von dieser Funktionalität integriert. Möchtest du diese integrierten Funktionen nutzen, kannst du dir mit
in der Bash einen ersten Überblick verschaffen. Noch zwei Anmerkungen zu deinem letzten Beispiel:
Bitte verinnerliche bereits in Beispielen, dass um Zuweisungsoperatoren keine Leerzeichen stehen dürfen. Das kann dir später nur helfen. ☺ Im Allgemeinen wird heute empfohlen, die erste Zeile mit #!/usr/bin/env bash zu starten (bash durch den jeweils richtigen Interpreter ersetzen), da das Programm /usr/bin/env zum POSIX-Standard gehört und deshalb auf wesentlich mehr Plattformen das richtige Programm findet. Mit #!/bin/bash kann es sein, dass du dich irgendwann mal wunderst, warum das Skript nicht geht (z.B. unter den BSD-Betriebssystemen).
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
ui schrieb: Schade nur, dass so etwas mit der Parameter Expansion nicht geht:
Wie schon weiter oben erwähnt (allerdings sehe ich gerade, dass das ein || statt einem && hätte sein sollen) kannst du auf einen Leeren String testen ( [ -n "$VAR" ] schaut, ob der String nicht null ist und [ -z "$VAR" ] schaut, ob er null ist) und darauf hin einen oder mehrere Befehle ausführen lassen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | #!/bin/bash
#Fehlerhafte Zuweisung:
VAR = Variableninhalt
mailAdmin(){
<E-Mail an Admin>
}
if [ -n "$VAR" ] ; then
<...>
else
mailAdmin
fi
|
|
JerryQuest
Anmeldungsdatum: 2. Mai 2008
Beiträge: 63
Wohnort: Wien
|
Ich hätte einen Praxistipp beizusteuern, der nicht viel Aufwand macht. Wenn ein script das Dateisystem ändern soll, zum Ausprobieren den eigentlichen Schreibbeefehl durch ls ersetzen und damit Testlauf durchführen. ls zeigt nicht nur das directory an, sondern verarbeitet auch alle möglichen Pfadbefehle usw. D.h. das script bleibt unverändert, nur statt rm -r $ZIEL/*; ganz einfach ls $ZIEL/*; Dann den Output im Terminal checken. Gibt ls dort den Inhalt des gewünschten Zielpfads aus - super! Steht dort nur der Inhalt von "/" oder so, weiß man "uups". Hat mich selbst schon ein oder zweimal vor genau so einem Problem gerettet ☺ Simpel, wenn man mal drauf gekommen ist. Hab ich aus dem Buch "The Linux Command Line" von William Shots.
|
ui
(Themenstarter)
Anmeldungsdatum: 22. November 2008
Beiträge: 603
|
Der Tipp ls zu nutzen ist wirklich sehr gut.
|