mike1963
Anmeldungsdatum: 28. August 2018
Beiträge: 19
|
Mich würde interessieren, wie ihr Shell-Scripte "sauber", d.h. robust, wartbar und soweit möglich systemunabhängig hinbekommt, welche "Tipps und Tricks" gibt's dazu? Bzw. auch, gibt es URLs die zu diesem Thema etwas brauchbares hergeben? Ich hab mir diese dazu rausgesucht: https://stackoverflow.com/questions/20034614/what-are-the-rules-to-write-robust-shell-scripts https://www.davidpashley.com/articles/writing-robust-shell-scripts/ https://kvz.io/blog/2013/11/21/bash-best-practices/ https://github.com/danfruehauf/Scripts/tree/master/bash_scripting_conventions https://bashinglinux.wordpress.com/2009/08/01/conventions/ Gibt's weitere gute Adressen, die einem dieses Thema näherbringen? Bzw. habe ich mir eine script-Vorlage erstellt, die dafür sorgen soll, dass meine scripte wenigstens halbwegs gleich aussehen und sauber/robust sind, ich poste die auch, vielleicht hat ja jemand noch gute Ideen/Verbesserungsvorschläge dazu: (Ergänzend: Die meisten Code-Fragmente davon sind nicht von mir, sondern im Netz "zusammengeklaut" und auf meine Bedürfnisse abgeändert 😉 ) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | #!/bin/env bash
# command table, see function on_exit
declare -a _exit_queue_commands
#===============================================================================
## Initialize script with some defaults & goodies
init_script() {
## Wenn Variable "DEBUG" von aussen gesetzt wird, schalte ich die Debug-Ausgaben ein ...
[[ $DEBUG ]] && {
export PS4="+ \e[1;30m[\t]\011\e[1;34mLine: \${LINENO}\e[0m \011 \${FUNCNAME[0]:+\e[0;35m\${FUNCNAME[0]}\e[1;30m()\e[0m:\011\011 }"
set -x
}
# Zu den set-optionen siehe http://www.tldp.org/LDP/abs/html/abs-guide.html#FC4UPD Table 33-1. Bash options
# bzw. auch http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -euo pipefail # -e (errexit) ... exit the script if any statement returns a non-true return value
# -u (nounset) ... Attempt to use undefined variable outputs error message, and forces an exit
# -o pipefail ... Causes a pipeline to return the exit status of the last command in the pipe
# that returned a non-zero return value.
}
#===============================================================================
## Usage - Ausgabe auf dem BS
usage() {
cat <<End-of-message
USAGE:
$(basename $0) [OPTIONS]
DESCRIPTION
TODO: Eine kurze Beschreibung dieses Scripts ...
OPTIONS
-a, --aopt
Testoption a
-B <string>, --Bopt <string>
Testoption B (erwartet einen Wert ...)
-h, --help
Gibt diese Hilfe aus, danach exit. Alle anderen übergebenen Optionen werden ignoriert.
End-of-message
exit 2
}
#===============================================================================
## Run commands before a script exits. Useful for cleaning up resources
## even if your script terminates early.
##
## Usage (quotes are optional):
## on_exit "command to be executed"
##
## Example:
## tempfile=$(mktemp) && on_exit rm -f ${tempfile}
##
on_exit() {
trap on_exit EXIT
if (( ${#} > 0 )); then
## While "${@}" is almost always the correct usage, using "${*}"
## here means quoting the "command to be executed" is optional.
_exit_queue_commands+=( "${*}" )
else
for task in "${_exit_queue_commands[@]}"; do
echo "Executing [${task}]"
eval "${task}"
done
## Wenn man on_exit auch "händisch" aufrufen will, muessen die folgenden
## drei Zeilen auskommentiert werden
# for index in "${!_exit_queue_commands[@]}" ; do
# unset -v '_exit_queue_commands[$index]'
# done
fi
}
#===============================================================================
main() {
# Ein Beispiel-getopts, weil ich das öfters brauche ... ;-)
local tmp_getopts
while getopts "haB: --long help,aopt,:Bopt:" tmp_getopts; do
case "${tmp_getopts}" in
h|-help)
usage
;;
a|-aopt)
option_a=yes;
shift 1
;;
B|-Bopt)
option_B=$2;
shift 2
;;
-)
shift;
break;;
*)
usage
;;
esac
done
## Nur als Beispiel lege ich hier zwei Arbeitsverzeichnisse an, welche
## durch die function "on_exit" automatisch geloescht werden
##
## Das funktioniert auch dann, wenn dieses script 'irgendwo' beendet wird
## und/oder abbricht (beispielsweise auch dann, wenn es von einem
## anderen user mittels "kill -9" abgebrochen wird).
## Man verhindert so also, dass sich "Mist" ansammelt ..
scratch1=$(mktemp -d -p ~/tmp) && on_exit rm -rf ${scratch1}
echo "Verzeichnis ${scratch1} angelegt ..."
scratch2=$(mktemp -d -p ~/tmp) && on_exit rm -rf ${scratch2}
echo "Verzeichnis ${scratch2} angelegt ..."
exit 0
}
#===============================================================================
init_script "$@"
main "$@"
|
Wenn jemand Ideen/Vorschläge zu diesem "Vorlagescript" bzw. Adressen/Vorschläge/... zum Thema robuste Shellscripte allgemein hat - Bitte, nur her damit. ☺
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Ich finde, in dem Skript ist zu viel Boilerplate. Eine Funktion, die man nur ein Mal aufruft, ist eigentlich überflüssig. Für ein simples Skript hast Du dann vielleicht viel mehr Overhead als eigentlich relevante Befehle. Ich würde die Shebang-Zeile nicht mit env schreiben, da die Pfade zu sh , bash usw. immer fest liegen. Es gibt da auch noch einen Bug in Deinem Skript: der trap für die Funktion on_exit() wird nie gesetzt und damit wird die Funktion nicht ausgeführt.
Eine wichtige Sache ist m.E. das Quoting sauber hinzubekommen. Insbesondere bei Dateinamen würde ich immer quoten, weil halt auch Leerzeichen oder anderes darin auftauchen kann. Ich habe in meinen Skripten meist diese Zeile oben nach dem Shebang: Damit kann man leicht Debugging einschalten und das gilt dann auch für andere Skripte, die von diesem aufgerufen werden. Es reicht dann ein Aufruf wie DEBUG=y das-skript und man bekommt die Ausgaben. Man kann dann auch basierend darauf, mittels Parameter Expansion vermehrte Ausgaben in anderen Programmen einschalten, z.B. | rsync -a --del --delete-excluded ${DEBUG:+-v} --progress ...
|
Wenn irgendetwas sehr kompakt programmiert werden musste, empfiehlt sich ein erklärender Kommentar. Wenn ich noch mehr darüber nachdenke, fällt mir bestimmt noch mehr ein. 😛
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2503
|
Vielleicht ganz allgemein:
Verstehe Shellskripte explizit als „Glue“ zwischen anderen Programmen.
Und sei dir über die Konsequenzen bewusst. Die Shell ist ziemlich gut darin¹, existierende Programme miteinander zu verbinden; sie ist aber kein allzu gutes Werkzeug, um welche zu schreiben. Spätestens, wenn du komplexere Datenstrukturen brauchst, bist du oft besser mit einer anderen Sprache bedient. Oder auch, wenn du systemnähere Funktionen benötigst. Oder wenn das Ding sehr lang wird, denn die Möglichkeiten des Namespacing / Scoping sind auch eher eingeschränkt (siehe zum Beispiel der inkonsequente Einsatz von „local “ in deinem Beispiel). Das mag trivial klingen, aber zumindest ich bin schon des öfteren in diese Falle getappt. Man fängt etwas als Shellskript an, dann wächst es ein bisschen und irgendwann merkt man, dass das eigentlich kein Shellskript mehr sein sollte. Der Übergang ist manchmal fließend. Dazu kommt, dass du auch komplexere Probleme durchaus als Shellskript lösen kannst (und das ist oftmals eine spannende Herausforderung, die Spaß macht), aber die Frage ist eben, ob das eine gute Idee ist. ☺ ¹ Wenn man von „modernem Firlefanz“ wie Parallelisierung absieht. Eine „for “-Schleife über ein paar Dateien ist in der Shell immer erstmal sequenziell. Das so hinzukriegen, dass immer genau so viele Jobs laufen, wie du Prozessoren zur Verfügung hast, ist dann schon recht anstrengend.
mike1963 schrieb: soweit möglich systemunabhängig
Damit meinst du „unabhängig von deinem konkreten Linux-Rechner“ und nicht „betriebssystemunabhängig, zum Beispiel portabel auf OpenBSD“, richtig?
|
mike1963
(Themenstarter)
Anmeldungsdatum: 28. August 2018
Beiträge: 19
|
rklm schrieb: Ich finde, in dem Skript ist zu viel Boilerplate. Eine Funktion, die man nur ein Mal aufruft, ist eigentlich überflüssig. Für ein simples Skript hast Du dann vielleicht viel mehr Overhead als eigentlich relevante Befehle.
Welche Funktion meinst Du? main? init_script? on_exit?
Es gibt da auch noch einen Bug in Deinem Skript: der trap für die Funktion on_exit() wird nie gesetzt und damit wird die Funktion nicht ausgeführt.
Doch, wird gesetzt, und zwar in der Funktion on_exit selbst, der allererste Befehl. Wird on_exit das erste mal aufgerufen - wird der trap gesetzt. Der "Fehler" (wenn man hier von einem Fehler sprechen will) ist höchstens, dass der gleiche trap u.U. öfters gesetzt wird, nämlich jedesmal wenn on_exit aufgerufen wird. Das ist vielleicht nicht die sauberste Lösung - funktioniert aber gut. Eine wichtige Sache ist m.E. das Quoting sauber hinzubekommen. Insbesondere bei Dateinamen würde ich immer quoten, weil halt auch Leerzeichen oder anderes darin auftauchen kann.
Stimmt, beim Quoten muss ich besser aufpassen ... Damit kann man leicht Debugging einschalten und das gilt dann auch für andere Skripte ...
Ich hab ziemlich die gleichen Zeilen in meinem Ding. Ich setze halt noch zusätzlich die bash-Variable PS4 😉 Wenn ich noch mehr darüber nachdenke, fällt mir bestimmt noch mehr ein. 😛
Bitte, nur her damit. ☺
|
mike1963
(Themenstarter)
Anmeldungsdatum: 28. August 2018
Beiträge: 19
|
Vain schrieb:
Das mag trivial klingen, aber zumindest ich bin schon des öfteren in diese Falle getappt. Man fängt etwas als Shellskript an, dann wächst es ein bisschen und irgendwann merkt man, dass das eigentlich kein Shellskript mehr sein sollte. Der Übergang ist manchmal fließend. Dazu kommt, dass du auch komplexere Probleme durchaus als Shellskript lösen kannst (und das ist oftmals eine spannende Herausforderung, die Spaß macht), aber die Frage ist eben, ob das eine gute Idee ist. ☺
👍 Ich habe in der Firma ein 800 Zeilen bash-script "geerbt", hab von Anfang an gesagt, dass das Ding mittlerweile unwartbar ist und eigentlich neu gemacht gehört, in java oder meinetwegen auch in perl - nur weil man's mit der bash (mit Array-Variablen und und und) "irgendwie" hinbekommt, heisst das noch lange nicht, dass es auch sinnvoll ist. Nach einiger Zeit in dem ich mich mit dem alten Ding rumärgern musste ... haben wir's dann neu gemacht, jetzt kann man's auch wieder "anschauen". 😉
mike1963 schrieb: soweit möglich systemunabhängig
Damit meinst du „unabhängig von deinem konkreten Linux-Rechner“ und nicht „betriebssystemunabhängig, zum Beispiel portabel auf OpenBSD“, richtig?
Ganz genau. Teilweise laufen Scripts auch auf Rechnern, die ich (wir) nicht beaufsichtige. Da ist dann nicht gewährleistet, dass meinetwegen das Programm "dialog" auch wirklich installiert ist - also kann ich das in Scripten die u.U. auch auf anderen Rechnern laufen nicht gebrauchen ...
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
mike1963 schrieb: rklm schrieb: Ich finde, in dem Skript ist zu viel Boilerplate. Eine Funktion, die man nur ein Mal aufruft, ist eigentlich überflüssig. Für ein simples Skript hast Du dann vielleicht viel mehr Overhead als eigentlich relevante Befehle.
Welche Funktion meinst Du? main? init_script? on_exit?
Ja.
Es gibt da auch noch einen Bug in Deinem Skript: der trap für die Funktion on_exit() wird nie gesetzt und damit wird die Funktion nicht ausgeführt.
Doch, wird gesetzt, und zwar in der Funktion on_exit selbst, der allererste Befehl. Wird on_exit das erste mal aufgerufen - wird der trap gesetzt.
Ja, aber das ist ja Blödsinn: Du willst ja einen Exit-Trap setzen, ohne ihn ausführen zu müssen. Die Funktion ist doch dafür gedacht aufzuräumen. Wenn man sie aufrufen muss, um sie für den Exit zu aktivieren, räumt sie ja schon weg, was man noch braucht.
Der "Fehler" (wenn man hier von einem Fehler sprechen will) ist höchstens, dass der gleiche trap u.U. öfters gesetzt wird, nämlich jedesmal wenn on_exit aufgerufen wird. Das ist vielleicht nicht die sauberste Lösung - funktioniert aber gut.
s.o.
Damit kann man leicht Debugging einschalten und das gilt dann auch für andere Skripte ...
Ich hab ziemlich die gleichen Zeilen in meinem Ding. Ich setze halt noch zusätzlich die bash-Variable PS4 😉
Nur, dass Du dafür erst eine Funktion aufrufen musst. Man will aber ja das ganze Skript debuggen. Also packt man das so nahe an den Anfang wie möglich.
|
mike1963
(Themenstarter)
Anmeldungsdatum: 28. August 2018
Beiträge: 19
|
rklm schrieb: mike1963 schrieb: rklm schrieb: Ich finde, in dem Skript ist zu viel Boilerplate. Eine Funktion, die man nur ein Mal aufruft, ist eigentlich überflüssig. Für ein simples Skript hast Du dann vielleicht viel mehr Overhead als eigentlich relevante Befehle.
Welche Funktion meinst Du? main? init_script? on_exit?
Ja.
Hmmmm ... ☺ Ich weiss ehrlich nicht, was hier der sauberste Weg ist. Den "overhead" einer zusätzlichen Funktion würde ich jedenfalls gerne in Kauf nehmen, wenn's dafür les- bzw. wartbarer wird (Ob ich das damit erreiche ist eine andere Frage. 😉) Vielleicht sind die vielen Funktionen bzw. deren Aufrufe übertrieben, ich hab mich dabei an diese Empfehlung gehalten: https://bashinglinux.wordpress.com/2009/08/01/conventions/
Before starting any Bash script, I have the following skeleton :
#!/bin/bash
main() {
}
main "$@"
Call me crazy, but without my main() function I ain’t going anywhere. Now we can start writing some bash. Once you have your main() it means you’re going to write code ONLY inside functions. I don’t care it’s a scripting language – let’s be strict.
Ist's Deiner Meinung nach übertrieben? Es gibt da auch noch einen Bug in Deinem Skript: der trap für die Funktion on_exit() wird nie gesetzt und damit wird die Funktion nicht ausgeführt.
Doch, wird gesetzt, und zwar in der Funktion on_exit selbst, der allererste Befehl. Wird on_exit das erste mal aufgerufen - wird der trap gesetzt.
Ja, aber das ist ja Blödsinn: Du willst ja einen Exit-Trap setzen, ohne ihn ausführen zu müssen. Die Funktion ist doch dafür gedacht aufzuräumen. Wenn man sie aufrufen muss, um sie für den Exit zu aktivieren, räumt sie ja schon weg, was man noch braucht.
Ich glaube, da irrst Du jetzt. Ich schreib nochmals nur die relevanten Statements raus: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 |
declare -a _exit_queue_commands
##============================================================================================================
on_exit() {
[mark]trap on_exit EXIT[/mark]
if (( ${#} > 0 )); then
_exit_queue_commands+=( "${*}" )
else
for task in "${_exit_queue_commands[@]}"; do
echo "Executing [${task}]"
eval "${task}"
done
fi
}
#===============================================================================
main() {
scratch1=$(mktemp -d -p ~/tmp) && on_exit rm -rf ${scratch1}
scratch2=$(mktemp -d -p ~/tmp) && on_exit rm -rf ${scratch1}
echo "Verzeichnis ${scratch1} und ${scratch2} angelegt. Die werden durch "on_exit" beim Beenden des Scripts wieder geloescht ..."
exit 0
}
#===============================================================================
main "$@"
|
Beim Anlegen des (Arbeits-)Verzeichnisses "$scratch1" und "$scratch2" (oder beliebiger anderer temporärer Verzeichnisse oder Files) sagt man also jeweils dazu: "Wenn das Script sich beendet ("on_exit"), dann lösche bitte dieses Arbeitsverzeichnis (oder mach beliebige andere Aufräumarbeiten). Man braucht sich später nicht mehr um dieses Verzeichnis/File zu kümmern. Der Vorteil ist klar: Temporärer Mist den das Script sonst vllt. hinterlassen würde, wird in jedem Fall gelöscht. Also auch dann wenn z.B. das Script während des Ablaufs mittels "kill" abgebrochen wurde. Und den Trap-Befehl braucht man nicht (nochmals) zu setzen, der wird beim Aufruf von on_exit gesetzt, also in der Funktion selbst. Bei JEDEM Aufruf, er wird also in dem Beispiel zweimal gesetzt, was vllt. nicht wirklich sehr sauber ist - aber wie gesagt bestens funktioniert. Alternativ müsste ich sowas machen: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | declare -a _exit_queue_commands
declare -i _on_exit_called=0
...
on_exit() {
[mark]if [ "$_on_exit_called" = 0 ]; then
_on_exit_called=1[/mark]
trap on_exit EXIT
fi
if (( ${#} > 0 )); then
_exit_queue_commands+=( "${*}" )
else
for task in "${_exit_queue_commands[@]}"; do
echo "Executing [${task}]"
eval "${task}"
done
}
|
Der "Fehler" (wenn man hier von einem Fehler sprechen will) ist höchstens, dass der gleiche trap u.U. öfters gesetzt wird, nämlich jedesmal wenn on_exit aufgerufen wird. Das ist vielleicht nicht die sauberste Lösung - funktioniert aber gut.
s.o.
Probier's einfach aus, ich schwöre, die "Aufräumfunktion" funktioniert bestens, keine Fehler. Wenn Du der Funktion nicht vertraust, kannst ja das "eval" zum Testen auskommentieren. ☺ Damit kann man leicht Debugging einschalten und das gilt dann auch für andere Skripte ...
Ich hab ziemlich die gleichen Zeilen in meinem Ding. Ich setze halt noch zusätzlich die bash-Variable PS4 😉
Nur, dass Du dafür erst eine Funktion aufrufen musst. Man will aber ja das ganze Skript debuggen. Also packt man das so nahe an den Anfang wie möglich.
s.o. - wobei ich wie gesagt ehrlich nicht wirklich beurteilen kann, wie gut der obige entsprechende Tip von bashinglinux.wordpress.com ("Alles in Funktionen! ...") tatsächlich ist ...
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
mike1963 schrieb: rklm schrieb: mike1963 schrieb: rklm schrieb:
Ich weiss ehrlich nicht, was hier der sauberste Weg ist. Den "overhead" einer zusätzlichen Funktion würde ich jedenfalls gerne in Kauf nehmen, wenn's dafür les- bzw. wartbarer wird (Ob ich das damit erreiche ist eine andere Frage. 😉)
Durch die Definition von Funktionen wird der Ablauf verschleiert. Du liest erst die Funktion, musst dann aber nachschauen, wo überall die aufgerufen wird. Wenn Du einfach das Skript herunterprogrammierst, also mit Initialisierungen am Anfang, dann Auswertung der Kommandozeile und dann der "main"-Teil, kann man von oben nach unten lesen und muss nicht springen. Ganz abgesehen davon: stell Dir vor, "main" besteht nur aus zwei Zeilen. Und dann schau Dir die Anzahl von Zeilen an, die zusätzlich durch die ganzen Kommentare und Funktionen immer da sind. Das ist unverhältnismäßig. Es geht hier um Skripte - keine Programme (wie ja auch schon angemerkt wurde).
Vielleicht sind die vielen Funktionen bzw. deren Aufrufe übertrieben, ich hab mich dabei an diese Empfehlung gehalten: https://bashinglinux.wordpress.com/2009/08/01/conventions/
Before starting any Bash script, I have the following skeleton :
#!/bin/bash
main() {
}
main "$@"
Call me crazy, but without my main() function I ain’t going anywhere. Now we can start writing some bash. Once you have your main() it means you’re going to write code ONLY inside functions. I don’t care it’s a scripting language – let’s be strict.
Ist's Deiner Meinung nach übertrieben?
Ja. Das ist so diese typische Art von Regel, die als allgemeingültig hingestellt wird. Der Wirklichkeit werden solche Regeln oft nicht gerecht. Und - wie gesagt - wir sprechen hier von Skripten.
Es gibt da auch noch einen Bug in Deinem Skript: der trap für die Funktion on_exit() wird nie gesetzt und damit wird die Funktion nicht ausgeführt.
Doch, wird gesetzt, und zwar in der Funktion on_exit selbst, der allererste Befehl. Wird on_exit das erste mal aufgerufen - wird der trap gesetzt.
Ja, aber das ist ja Blödsinn: Du willst ja einen Exit-Trap setzen, ohne ihn ausführen zu müssen. Die Funktion ist doch dafür gedacht aufzuräumen. Wenn man sie aufrufen muss, um sie für den Exit zu aktivieren, räumt sie ja schon weg, was man noch braucht.
Ich glaube, da irrst Du jetzt. Ich schreib nochmals nur die relevanten Statements raus:
Du hast Recht, den Teil habe ich übersehen. Aber: die Funktion on_exit() verletzt ein grundlegendes Prinzip, dass nämlich eine Funktion eine Sache machen soll. In Deinem Fall tut sie zwei Dinge (Registrieren und Aufräumen) und so etwas erhöht die Komplexität und erzeugt unnötige Abhängigkeiten. Ganz abgesehen davon, dass ein Mechanismus, der die Registrierung beliebiger Kommandos erlaubt, für ein Skript in meiner Welt unnötig ist. Ich habe so etwas in Shell-Skripten jedenfalls noch nicht gebraucht. Wenn ich wirklich mehrere temporäre Dateien benötige, dann sieht das bei mir eher so aus: 1
2
3
4
5
6
7
8
9
10
11
12 | tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' 0
# ...
work="$tmpdir/work"
whatever >|"$work"
more_work="$tmpdir/more_work"
something else >| "$more_work"
|
Der Vorteil ist klar: Temporärer Mist den das Script sonst vllt. hinterlassen würde, wird in jedem Fall gelöscht. Also auch dann wenn z.B. das Script während des Ablaufs mittels "kill" abgebrochen wurde.
Das steht auch überhaupt nicht in Frage.
Damit kann man leicht Debugging einschalten und das gilt dann auch für andere Skripte ...
Ich hab ziemlich die gleichen Zeilen in meinem Ding. Ich setze halt noch zusätzlich die bash-Variable PS4 😉
Nur, dass Du dafür erst eine Funktion aufrufen musst. Man will aber ja das ganze Skript debuggen. Also packt man das so nahe an den Anfang wie möglich.
s.o. - wobei ich wie gesagt ehrlich nicht wirklich beurteilen kann, wie gut der obige entsprechende Tip von bashinglinux.wordpress.com ("Alles in Funktionen! ...") tatsächlich ist ...
Man kann so etwas praktisch automatisch beantworten: wenn eine Regel ohne Ausnahmen angegeben wird, die angeblich immer gelten soll, ist Vorsicht angesagt. Das zeigt in meinen Augen, dass der Autor sich nicht bewusst ist, dass die Wirklichkeit komplexer ist als die Einfachheit solcher Regeln suggeriert. Nach meiner Erfahrung mögen Menschen, die sich zum Programmieren hingezogen fühlen, solche einfachen und klaren Regeln. Die werden der Wirklichkeit aber meist nicht gerecht.
|