Bei der Arbeit schreibe ich häufig Bash-Skripte. Mein Vorgesetzter hat vorgeschlagen, das gesamte Skript in Funktionen zu unterteilen, ähnlich wie im folgenden Beispiel:
#!/bin/bash # Configure variables declare_variables() { noun=geese count=three } # Announce something i_am_foo() { echo "I am foo" sleep 0.5 echo "hear me roar!" } # Tell a joke walk_into_bar() { echo "So these ${count} ${noun} walk into a bar..." } # Emulate a pendulum clock for a bit do_baz() { for i in {1..6}; do expr $i % 2 >/dev/null && echo "tick" || echo "tock" sleep 1 done } # Establish run order main() { declare_variables i_am_foo walk_into_bar do_baz } main
Gibt es einen anderen Grund als „Lesbarkeit“? , was meiner Meinung nach mit ein paar weiteren Kommentaren und einem gewissen Zeilenabstand genauso gut etabliert werden könnte?
Lässt es das Skript effizienter laufen (ich würde tatsächlich das Gegenteil erwarten, wenn überhaupt), oder macht es das? Ist es einfacher, den Code über das oben genannte Lesbarkeitspotential hinaus zu ändern? Oder ist es wirklich nur eine stilistische Präferenz?
Bitte beachten Sie, dass das Skript zwar nicht gut demonstriert, die „Ausführungsreihenfolge“ der Funktionen in unseren tatsächlichen Skripten jedoch sehr linear ist – walk_into_bar
hängt von Dingen ab, die i_am_foo
erledigt hat, und do_baz
wirkt auf Dinge, die von walk_into_bar
– die Möglichkeit, die Ausführungsreihenfolge willkürlich auszutauschen, ist also nichts, was wir normalerweise tun würden. Zum Beispiel möchten Sie declare_variables
nicht plötzlich nach walk_into_bar
setzen, was die Dinge kaputt machen würde.
An Ein Beispiel dafür, wie ich das obige Skript schreiben würde, wäre:
#!/bin/bash # Configure variables noun=geese count=three # Announce something echo "I am foo" sleep 0.5 echo "hear me roar!" # Tell a joke echo "So these ${count} ${noun} walk into a bar..." # Emulate a pendulum clock for a bit for i in {1..6}; do expr $i % 2 >/dev/null && echo "tick" || echo "tock" sleep 1 done
Kommentare
- Ich mag Ihre Boss. In meinen Skripten habe ich auch
main()
oben undmain "$@"
unten eingefügt, um es aufzurufen. So können Sie das Hoch sehen Level-Skript-Logik als erstes, wenn Sie es öffnen. - Ich bin nicht der Meinung, dass die Lesbarkeit “ mit ein paar weiteren Kommentaren und einigen Zeilenabständen gleichermaßen gut festgelegt werden kann “ Außer vielleicht für Fiktion würde ich ‚ nicht mit einem Buch umgehen wollen, das nicht ‚ Es gibt kein Inhaltsverzeichnis und keine beschreibenden Namen für jedes Kapitel und jeden Abschnitt. In Programmiersprachen ist ‚ die Art von Lesbarkeit, die Funktionen bieten können, a nd Kommentar ‚ s können ‚ t.
- Beachten Sie, dass in Funktionen deklarierte Variablen deklariert werden sollten
local
– Dies bietet einen variablen Bereich , der in jedem nicht trivialen Skript unglaublich wichtig ist. - Ich bin mit Ihrem Chef nicht einverstanden. Wenn Sie Ihr Skript in Funktionen aufteilen müssen, sollten Sie ‚ wahrscheinlich überhaupt kein Shell-Skript schreiben. Schreiben Sie stattdessen ein Programm.
- Funktionen gelten für Prozesse, die entweder innerhalb des Skripts oder in mehr als einem Skript wiederholt werden. Sie ermöglichen auch die Einführung einheitlicher Methoden. Zum Beispiel mit einer Funktion zum Schreiben in Syslog. Solange alle dieselbe Funktion verwenden, sind Ihre Syslog-Einträge konsistenter. Einmalfunktionen wie Ihr Beispiel erschweren das Skript unnötig. In einigen Fällen führen sie zu Problemen (variabler Gültigkeitsbereich).
Antwort
Ich habe damit begonnen, dasselbe zu verwenden Stil der Bash-Programmierung nach dem Lesen von Kfir Lavis Blog-Beitrag „Defensive Bash Programming“ . Er gibt einige gute Gründe an, aber ich persönlich finde diese am wichtigsten:
-
Prozeduren werden beschreibend: Es ist viel einfacher herauszufinden, was ein bestimmter Teil des Codes sein soll Anstelle der Codewand sehen Sie „Oh, die Funktion
find_log_errors
liest diese Protokolldatei auf Fehler“. Vergleichen Sie sie mit der Suche nach einer ganzen Reihe von awk / grep / sed-Zeilen, die Verwenden Sie Gott weiß, welche Art von Regex in der Mitte eines langen Skripts – Sie haben keine Ahnung, was es dort tut, es sei denn, es gibt Kommentare. -
Sie können Funktionen debuggen durch Einschließen in
set -x
undset +x
. Sobald Sie wissen, dass der Rest des Codes in Ordnung ist, können Sie diesen Trick verwenden, um sich darauf zu konzentrieren, nur diese bestimmte Funktion zu debuggen. Sicher, Sie können Teile des Skripts einschließen, aber was ist, wenn es „ein langer Teil“ ist? Es ist einfacher, so etwas zu tun:set -x parse_process_list set +x
-
Drucknutzung mit
cat <<- EOF . . . EOF
. Ich habe es einige Male verwendet, um meinen Code viel professioneller zu gestalten. Außerdem istparse_args()
mit der Funktiongetopts
sehr praktisch. Auch dies hilft bei der Lesbarkeit, anstatt alles als riesige Textwand in ein Skript zu verschieben. Es ist auch praktisch, diese wiederzuverwenden.
Und natürlich ist dies viel mehr lesbar für jemanden, der C oder Java oder Vala kennt, aber nur begrenzte Bash-Erfahrung hat. Was die Effizienz angeht, gibt es nicht viel, was Sie tun können – Bash selbst ist nicht die effizienteste Sprache, und die Leute bevorzugen Perl und Python, wenn es um Geschwindigkeit und Effizienz geht.Sie können jedoch nice
eine Funktion ausführen:
nice -10 resource_hungry_function
Im Vergleich zum Aufruf von nice in jeder einzelnen Codezeile Dies verringert die gesamte Eingabe und kann bequem verwendet werden, wenn nur ein Teil Ihres Skripts mit niedrigerer Priorität ausgeführt werden soll.
Das Ausführen von Funktionen im Hintergrund ist meiner Meinung nach auch hilfreich, wenn Sie ein Ganzes haben möchten Eine Reihe von Anweisungen, die im Hintergrund ausgeführt werden sollen.
Einige Beispiele, in denen ich diesen Stil verwendet habe:
- https://askubuntu.com/a/758339/295286
- https://askubuntu.com/a/788654/295286
- https://github.com/SergKolo/sergrep/blob/master/chgreeterbg.sh
Kommentare
- Ich bin mir nicht sicher, ob Sie Vorschläge aus diesem Artikel sehr ernst nehmen sollten. Zugegeben, es hat ein paar gute Ideen, aber es ist eindeutig nicht jemand, der an Shell-Scripting gewöhnt ist. Kein
single in einem der Beispiele wird mit (!) angegeben und schlägt die Verwendung von UPPER C vor ASE-Variablennamen, was oft eine sehr schlechte Idee ist, da sie mit vorhandenen env-Variablen in Konflikt stehen können. Ihre Punkte in dieser Antwort sind sinnvoll, aber der verlinkte Artikel scheint von jemandem geschrieben worden zu sein, der nur an andere Sprachen gewöhnt ist und versucht, seinen Stil der Bash aufzuzwingen. - @terdon Ich ging zurück zum Artikel und las ihn noch einmal. Der einzige Ort, an dem der Autor die Benennung von Variablen in Großbuchstaben erwähnt, ist “ Unveränderliche globale Variablen „. Wenn Sie globale Variablen als solche betrachten, die sich in der Umgebung der Funktion ‚ befinden müssen, ist es sinnvoll, sie groß zu schreiben. Nebenbei bemerkt, das Handbuch von bash ‚ enthält keine ‚ t-Zustandskonvention für variablen Fall. Sogar hier akzeptierte Antwort sagt “ normalerweise “ und die einzige “ Standard “ stammt von Google, das nicht ‚ die gesamte IT-Branche repräsentiert.
- @terdon in einem anderen Punkt stimme ich zu 100% zu, dass das Zitieren von Variablen in dem Artikel hätte erwähnt werden sollen, und es wurde auch in den Kommentaren im Blog darauf hingewiesen. Außerdem würde ich ‚ niemanden beurteilen, der diesen Codierungsstil verwendet, unabhängig davon, ob er ‚ in einer anderen Sprache verwendet wird oder nicht. Diese ganze Frage und die Antworten zeigen deutlich die Vorteile von ‚ und den Grad der Person ‚, in dem sie ‚ die Verwendung in einer anderen Sprache ist hier wahrscheinlich irrelevant.
- @terdon Nun, der Artikel wurde als Teil der “ -Quelle “ Material. Ich hätte alles als meine eigene Meinung veröffentlichen können, aber ich musste nur anerkennen, dass einige der Dinge, die ich aus dem Artikel gelernt habe, und dass all dies aus Recherchen im Laufe der Zeit stammte. Die Linkedin-Seite des Autors ‚ zeigt, dass er gute Erfahrungen mit Linux und IT im Allgemeinen hat. Ich ‚ schätze, dass der Artikel nicht ‚ zeigt das nicht wirklich, aber ich vertraue auf Ihre Erfahrung mit Linux und Shell-Scripting, sodass Sie möglicherweise Recht haben.
- Das ‚ ist eine ausgezeichnete Antwort, aber ich ‚ möchte auch hinzufügen, dass der variable Bereich in Bash funky ist. Aus diesem Grund deklariere ich meine Variablen lieber innerhalb von Funktionen mit
local
und rufe alles über die Funktionmain()
auf. Dies macht die Dinge viel einfacher zu handhaben und Sie können eine möglicherweise unordentliche Situation vermeiden.
Antwort
Lesbarkeit ist eine Sache. Modularisierung bietet jedoch mehr als nur dies. ( Semimodularisierung ist für Funktionen möglicherweise korrekter.)
In Funktionen können Sie einige Variablen lokal halten, wodurch die Zuverlässigkeit erhöht und die Wahrscheinlichkeit von verringert wird Dinge werden durcheinander gebracht.
Ein weiterer Vorteil von Funktionen ist die Wiederverwendbarkeit . Sobald eine Funktion codiert ist, kann sie im Skript mehrmals angewendet werden. Sie können es auch auf ein anderes Skript portieren.
Ihr Code ist jetzt möglicherweise linear, aber in Zukunft können Sie in den Bereich Multithreading oder Multithreading eintreten. Verarbeitung in der Bash-Welt. Sobald Sie gelernt haben, Dinge in Funktionen zu tun, sind Sie für den Schritt in die Parallele gut gerüstet.
Ein weiterer Punkt, den Sie hinzufügen müssen. Wie Etsitpab Nioliv im folgenden Kommentar bemerkt, ist es einfach, von Funktionen als kohärente Einheit umzuleiten. Es gibt jedoch noch einen weiteren Aspekt der Umleitung mit Funktionen. Die Umleitungen können nämlich entlang der Funktionsdefinition festgelegt werden. Beispiel:
f () { echo something; } > log
Jetzt sind für die Funktionsaufrufe keine expliziten Umleitungen erforderlich.
$ f
Dies kann viele Wiederholungen ersparen, was wiederum die Zuverlässigkeit erhöht und dazu beiträgt, die Dinge in Ordnung zu halten.
Siehe auch
Kommentare
- Sehr gut Antworten Sie, obwohl es viel besser wäre, wenn es in Funktionen unterteilt wäre.
- Wenn Sie diese Funktionen hinzufügen, können Sie dieses Skript in ein anderes Skript importieren (mithilfe von
source
oder. scriptname.sh
und verwenden Sie diese Funktionen so, als wären sie in Ihrem neuen Skript enthalten. - Das ‚ wird bereits behandelt in einer anderen Antwort.
- Ich weiß das zu schätzen. Aber ich ‚ möchte lieber, dass auch andere Menschen wichtig sind.
- Ich stand vor einem Fall Heute musste ich einen Teil der Ausgabe eines Skripts in eine Datei umleiten (um sie per E-Mail zu senden), anstatt sie zu wiederholen. Ich musste einfach myFunction > myFile, um die Ausgabe der gewünschten Funktionen umzuleiten. Ziemlich praktisch. Könnte relevant sein.
Antwort
In meinem Kommentar habe ich drei Vorteile von Funktionen erwähnt:
-
Sie sind einfacher zu testen und die Richtigkeit zu überprüfen.
-
Funktionen können in zukünftigen Skripten problemlos wiederverwendet (bezogen) werden.
-
Ihr Chef mag sie.
Und unterschätzen Sie niemals die Bedeutung von Nummer 3.
Ich möchte noch ein Problem ansprechen:
… es ist also nichts, was wir normalerweise tun würden, wenn wir die Ausführungsreihenfolge willkürlich austauschen könnten. Zum Beispiel möchten Sie
declare_variables
nicht plötzlich nachwalk_into_bar
setzen, da dies zu Problemen führen würde.
Um den Code in Funktionen aufteilen zu können, sollte versucht werden, die Funktionen so unabhängig wie möglich zu gestalten. Wenn walk_into_bar
eine Variable benötigt, die Wird diese Variable nicht anderweitig verwendet, sollte sie in walk_into_bar
definiert und lokalisiert werden. Der Prozess des Aufteilens des Codes in Funktionen und des Minimierens ihrer gegenseitigen Abhängigkeiten sollte den Code klarer und einfacher machen
Im Idealfall sollten Funktionen einfach einzeln zu testen sein. Wenn sie aufgrund von Interaktionen nicht einfach zu testen sind, ist dies ein Zeichen dafür, dass sie möglicherweise von Refactoring profitieren.
Kommentare
- Ich ‚ würde argumentieren, dass es manchmal sinnvoll ist, ‚ zu modellieren und erzwingen Sie diese Abhängigkeiten im Vergleich zum Refactoring, um sie zu vermeiden (da, wenn es genug gibt h von ihnen, und sie ‚ sind ausreichend behaart, was nur zu einem Fall führen kann, in dem die Dinge überhaupt nicht mehr in Funktionen modularisiert werden). Ein sehr komplizierter Anwendungsfall hat einmal ein Framework dazu inspiriert, genau das zu tun .
- Was in Funktionen unterteilt werden muss, sollte das Beispiel sein geht es zu weit. Ich denke, das einzige, was mich wirklich nervt, ist die Variablendeklarationsfunktion. Globale Variablen, insbesondere statische, sollten global in einem Kommentarbereich definiert werden, der diesem Zweck gewidmet ist. Dynamische Variablen sollten lokal für die Funktionen sein, die sie verwenden und ändern.
- @Xalorous I ‚ habe eine Vorgehensweise gesehen, bei der globale Variablen initialisiert werden in einer Prozedur als Zwischen- und Schnellschritt vor der Entwicklung einer Prozedur, die ihren Wert aus einer externen Datei liest … Ich stimme zu, dass es sauberer sein sollte, Definition und Initialisierung zu trennen, aber selten muss man sich biegen, um sich der zu unterziehen Vorteil Nummer 3
;-)
Antwort
Ich stimme vollkommen zu mit der Wiederverwendbarkeit , Lesbarkeit und dem zarten Küssen der Bosse, aber es gibt noch einen weiteren Vorteil von Funktionen in bash : variabler Bereich . Wie LDP zeigt :
#!/bin/bash # ex62.sh: Global and local variables inside a function. func () { local loc_var=23 # Declared as local variable. echo # Uses the "local" builtin. echo "\"loc_var\" in function = $loc_var" global_var=999 # Not declared as local. # Therefore, defaults to global. echo "\"global_var\" in function = $global_var" } func # Now, to see if local variable "loc_var" exists outside the function. echo echo "\"loc_var\" outside function = $loc_var" # $loc_var outside function = # No, $loc_var not visible globally. echo "\"global_var\" outside function = $global_var" # $global_var outside function = 999 # $global_var is visible globally. echo exit 0 # In contrast to C, a Bash variable declared inside a function #+ is local ONLY if declared as such.
Ich sehe dies in der realen Welt nicht sehr oft Shell-Skripte, aber es scheint eine gute Idee für komplexere Skripte zu sein. Wenn Sie die -Kohäsion reduzieren, können Sie Fehler vermeiden, bei denen Sie eine in einem anderen Teil des Codes erwartete Variable überladen .
Wiederverwendbarkeit bedeutet häufig, eine gemeinsame Funktionsbibliothek zu erstellen und source
diese Bibliothek in alle Ihre Skripte zu unterteilen. Dies hilft ihnen nicht, schneller zu laufen, aber es hilft Ihnen, sie schneller zu schreiben.
Kommentare
- Nur wenige Leute verwenden explizit
local
, aber ich denke, die meisten Leute, die Skripte schreiben, die in Funktionen unterteilt sind, folgen immer noch dem Entwurfsprinzip. Usignlocal
macht es nur schwieriger, Fehler einzuführen. -
local
stellt Variablen für die Funktion und ihre untergeordneten Elemente zur Verfügung. ‚ ist wirklich schön, eine Variable zu haben, die übergeben werden kann nach unten von Funktion A, aber nicht verfügbar für Funktion B, die möglicherweise eine Variable mit demselben Namen, aber unterschiedlichem Zweck haben möchte.Damit ‚ gut für die Definition des Bereichs geeignet ist und wie Voo sagte – weniger Fehler
Antwort
Sie teilen den Code aus demselben Grund in Funktionen auf, aus dem Sie dies für C / C ++, Python, Perl, Ruby oder einen anderen Programmiersprachencode tun würden. Der tiefere Grund ist die Abstraktion: Sie kapseln Aufgaben auf niedrigerer Ebene in Grundelemente (Funktionen) auf höherer Ebene, sodass Sie sich nicht darum kümmern müssen, wie die Dinge erledigt werden. Gleichzeitig wird der Code lesbarer (und wartbarer) Die Programmlogik wird klarer.
Wenn ich jedoch Ihren Code betrachte, finde ich es ziemlich seltsam, eine Funktion zum Deklarieren von Variablen zu haben, was mich wirklich dazu bringt, die Augenbrauen hochzuziehen.
Kommentare
Antwort
Ein völlig anderer Grund als der, der bereits in anderen Antworten angegeben wurde: Ein Grund, warum diese Technik manchmal verwendet wird, wo die Sohle Die Nicht-Funktionsdefinitionsanweisung auf oberster Ebene ist ein Aufruf von main
, um sicherzustellen, dass das Skript nicht versehentlich etwas Böses tut, wenn das Skript abgeschnitten wird. Das Skript wird möglicherweise abgeschnitten wenn es so ist Weiterleitung von Prozess A an Prozess B (die Shell), und Prozess A wird aus irgendeinem Grund beendet, bevor das gesamte Skript fertig geschrieben wurde. Dies ist besonders wahrscheinlich, wenn Prozess A das Skript von einer Remote-Ressource abruft. Aus Sicherheitsgründen ist dies zwar keine gute Idee, wird jedoch durchgeführt, und einige Skripts wurden geändert, um das Problem zu antizipieren.
Kommentare
- nteressant! Aber ich finde es beunruhigend, dass man sich in jedem der Programme um diese Dinge kümmern muss. Andererseits ist genau dieses
- Die Python-Redewendung hat den Vorteil, dass andere Skripte
import
das aktuelle Skript ausführen können, ohnemain
auszuführen. Ich nehme an, ein ähnlicher Wächter könnte in ein Bash-Skript eingefügt werden. - @Jake Cobb Ja. Ich mache das jetzt in allen neuen Bash-Skripten. Ich habe ein Skript, das eine Kerninfrastruktur von Funktionen enthält, die von allen neuen Skripten verwendet werden. Dieses Skript kann bezogen oder ausgeführt werden. Wenn bezogen, wird seine Hauptfunktion nicht ausgeführt. Die Erkennung von Quelle und Ausführung erfolgt über die Tatsache, dass BASH_SOURCE den Namen des ausführenden Skripts enthält. Wenn ‚ mit dem Kernskript identisch ist, wird das Skript ausgeführt. Andernfalls wird ‚ bezogen.
- In engem Zusammenhang mit dieser Antwort verwendet bash eine einfache zeilenbasierte Verarbeitung, wenn eine Datei ausgeführt wird, die sich bereits auf der Festplatte befindet. Wenn sich die Datei ändert, während das Skript ausgeführt wird, ändert sich der Zeilenzähler nicht ‚ und ‚ wird in der falschen Zeile fortgesetzt. Wenn Sie alles in Funktionen kapseln, wird sichergestellt, dass ‚ alles in den Speicher geladen wird, bevor etwas ausgeführt wird. Das Ändern der Datei hat also keine Auswirkungen darauf. li>
main()
Muster in Python üblich, wo am Ende der Datei if __name__ == '__main__': main()
verwendet wird.
Antwort
Einige relevante Binsenweisheiten zur Programmierung:
- Ihr Programm ändert sich, , auch wenn Ihr Chef darauf besteht, dass dies nicht der Fall ist.
- Nur Code und Eingabe beeinflussen das Verhalten des Programms.
- zu benennen ist schwierig.
Kommentare beginnen als Lücke, um nicht zu sein in der Lage, Ihre Ideen klar in Code * auszudrücken und mit Änderungen schlechter (oder einfach falsch) zu werden. Drücken Sie daher, wenn möglich, Konzepte, Strukturen, Argumentation, Semantik, Ablauf, Fehlerbehandlung und alles andere aus, was für das Verständnis des Codes als Code relevant ist.
Bash-Funktionen haben einige Probleme, die in den meisten Sprachen nicht zu finden sind:
- Namespacing ist in Bash schrecklich. Wenn Sie beispielsweise vergessen, das Schlüsselwort
local
zu verwenden, wird der globale Namespace verschmutzt. - Wenn Sie
local foo="$(bar)"
verwenden, erhalten Sie verliert den Exit-Code vonbar
. - Es gibt keine benannte Parameter, daher müssen Sie bedenken, was
"$@"
in verschiedenen Kontexten bedeutet.
* Es tut mir leid, wenn dies beleidigt, aber danach Verwenden von Kommentaren für einige Jahre und Entwickeln ohne sie ** für weitere Jahre ist es ziemlich klar, was überlegen ist.
** Das Verwenden von Kommentaren für die Lizenzierung, API-Dokumentation und dergleichen ist weiterhin erforderlich.
Kommentare
- Ich habe fast alle lokalen Variablen gesetzt, indem ich sie zu Beginn der Funktion auf null deklariert habe …
local foo=""
Setzen Sie sie dann mithilfe der Befehlsausführung, um auf das Ergebnis zu reagieren …foo="$(bar)" || { echo "bar() failed"; return 1; }
. Dies bringt uns schnell aus der Funktion heraus, wenn ein erforderlicher Wert nicht eingestellt werden kann. Die geschweiften Klammern sind erforderlich, um sicherzustellen, dass diereturn 1
nur bei einem Fehler ausgeführt wird. - Ich wollte nur Ihre Aufzählungspunkte kommentieren. Wenn Sie ‚ Subshell-Funktionen ‚ (Funktionen in Klammern und nicht in geschweiften Klammern) verwenden, 1) don ‚ muss nicht local verwenden, sondern die Vorteile von local nutzen. 2) ‚ stößt nicht auf das Problem, den Exit-Code der Befehlssubstitution in
local foo=$(bar)
so viel (weil Sie ‚ kein lokales verwenden) 3) Machen Sie sich keine Sorgen
über versehentliche Verschmutzung oder Änderung des globalen Bereichs 4) können ‚ benannte Parameter ‚ übergeben, die ‚ local ‚ für Ihre Funktion mithilfe der Syntaxfoo=bar baz=buz my-command
Antwort
Ein Prozess erfordert eine Sequenz. Die meisten Aufgaben sind sequentiell. Es macht keinen Sinn, sich mit der Bestellung anzulegen.
Aber das Super große an der Programmierung – einschließlich Skripten – ist das Testen. Testen, testen, testen. Welche Testskripte müssen Sie derzeit überprüfen, um die Richtigkeit Ihrer Skripte zu überprüfen?
Ihr Chef versucht, Sie vom Skriptkind zum Programmierer zu führen. Dies ist eine gute Richtung. Leute, die nach dir kommen, werden dich mögen.
ABER. Denken Sie immer an Ihre prozessorientierten Wurzeln. Wenn es sinnvoll ist, die Funktionen in der Reihenfolge zu ordnen, in der sie normalerweise ausgeführt werden, tun Sie dies zumindest als ersten Durchgang.
Später werden Sie feststellen, dass einige Ihrer Funktionen vorhanden sind Eingaben verarbeiten, andere ausgeben, andere verarbeiten, andere Daten modellieren und andere die Daten manipulieren. Daher kann es sinnvoll sein, ähnliche Methoden zu gruppieren und sie möglicherweise sogar in separate Dateien zu verschieben.
Später können Sie dies noch tun Stellen Sie fest, dass Sie jetzt Bibliotheken mit kleinen Hilfsfunktionen geschrieben haben, die Sie in vielen Ihrer Skripte verwenden.
Antwort
Kommentare und der Abstand kann nicht an die Lesbarkeit heranreichen, die Funktionen bieten können, wie ich zeigen werde. Ohne Funktionen können Sie den Wald vor lauter Bäumen nicht sehen – große Probleme verbergen sich in vielen Detailzeilen. Mit anderen Worten, die Leute können sich nicht gleichzeitig auf die feinen Details und das Gesamtbild konzentrieren. Das ist in einem kurzen Skript möglicherweise nicht offensichtlich. Solange es kurz bleibt, ist es möglicherweise lesbar genug. Die Software wird jedoch größer und nicht kleiner und sicherlich ist es Teil des gesamten Softwaresystems Ihres Unternehmens, das sicherlich sehr viel größer ist, wahrscheinlich Millionen von Zeilen.
Überlegen Sie, ob ich Ihnen Anweisungen wie diese gegeben habe:
Place your hands on your desk. Tense your arm muscles. Extend your knee and hip joints. Relax your arms. Move your arms backwards. Move your left leg backwards. Move your right leg backwards. (continue for 10,000 more lines)
Bis Sie zur Hälfte oder sogar zu 5% fertig waren, hätten Sie die ersten Schritte vergessen. Sie konnten möglicherweise die meisten Probleme nicht erkennen, weil Sie den Wald vor lauter Bäumen nicht sehen konnten. Vergleichen Sie mit Funktionen:
stand_up(); walk_to(break_room); pour(coffee); walk_to(office);
Das ist sicherlich viel verständlicher, egal wie viele Kommentare Sie in die zeilenweise sequentielle Version einfügen Außerdem ist es weitaus wahrscheinlicher, dass Sie vergessen, den Kaffee zuzubereiten, und wahrscheinlich Sit_down () am Ende vergessen. Wenn Ihr Verstand an die Details von Grep- und Awk-Regexen denkt, können Sie nicht an ein großes Bild denken – was ist, wenn kein Kaffee hergestellt wird?
Mit Funktionen können Sie in erster Linie das große Bild sehen. und beachten Sie, dass Sie vergessen haben, den Kaffee zuzubereiten (oder dass jemand Tee bevorzugt). Zu einem anderen Zeitpunkt sorgen Sie sich in einer anderen Stimmung um die detaillierte Implementierung.
Es gibt auch andere Vorteile, die in besprochen werden Andere Antworten natürlich. Ein weiterer Vorteil, der in den anderen Antworten nicht klar angegeben ist, besteht darin, dass Funktionen eine Garantie bieten, die für die Verhinderung und Behebung von Fehlern wichtig ist. Wenn Sie feststellen, dass eine Variable $ foo in der richtigen Funktion walk_to () falsch war, wissen Sie, dass Sie nur die anderen 6 Zeilen dieser Funktion betrachten müssen, um alles zu finden, was von diesem Problem betroffen sein könnte, und alles, was könnte habe dafür gesorgt, dass es falsch ist. Ohne (richtige) Funktionen kann alles und jedes im gesamten System dazu führen, dass $ foo falsch ist, und alles und jedes kann von $ foo betroffen sein. Daher können Sie $ foo nicht sicher reparieren, ohne jede einzelne Zeile des Programms erneut zu untersuchen. Wenn $ foo für eine Funktion lokal ist, können Sie sicherstellen, dass alle Änderungen sicher und korrekt sind, indem Sie nur diese Funktion überprüfen.
Kommentare
- Dies ist keine ‚ t
bash
-Syntax.Es ist allerdings eine Schande, ‚; Ich glaube nicht, dass es eine Möglichkeit gibt, Eingaben an solche Funktionen zu übergeben. ‚ (d. h.pour();
<coffee
). Es sieht eher aus wiec++
oderphp
(glaube ich). - @ tjt263 ohne die Klammern, es ‚ s Bash-Syntax: Kaffee einschenken. Bei parens ist es ‚ so ziemlich jede andere Sprache. 🙂
Antwort
Zeit ist Geld
Es gibt andere gute Antworten , die Aufschluss über die technischen Gründe geben, ein Skript möglicherweise modular zu schreiben lang, entwickelt in einer Arbeitsumgebung, entwickelt, um von einer Gruppe von Personen und nicht nur für Ihren eigenen Gebrauch verwendet zu werden.
Ich möchte konzentrieren sich auf eine Erwartung: In einer Arbeitsumgebung „Zeit ist Geld“ . Das Fehlen von Fehlern und die Leistung Ihres Codes werden daher zusammen mit Lesbarkeit , Testbarkeit, Wartbarkeit, Refaktorierbarkeit, Wiederverwendbarkeit …
Schreiben in “ Module „ Ein Code verringert die Lesezeit, die nicht nur vom Codierer selbst benötigt wird, sondern auch von den Testern oder von der Chef. Beachten Sie außerdem, dass die Zeit eines Chefs normalerweise mehr als die Zeit eines Programmierers bezahlt wird und dass Ihr Chef die Qualität Ihres Jobs bewertet.
Schreiben Sie außerdem in unabhängige „Module“ Mit einem Code (sogar einem Bash-Skript) können Sie „parallel“ arbeiten Eine andere Komponente Ihres Teams verkürzt die Gesamtproduktionszeit und nutzt bestenfalls das Fachwissen der einzelnen Mitarbeiter, um ein Teil ohne Nebenwirkungen für die anderen zu überprüfen oder neu zu schreiben und den soeben geschriebenen Code „so wie er ist“
Die Einhaltung eines -Standards verlangsamt Ihre Arbeit am Anfang, aber es wird die Arbeit aller anderen (und auch Ihrer) danach beschleunigen. In der Tat wird dies zu einem unvermeidlichen Bedürfnis, wenn die Anzahl der beteiligten Personen an der Zusammenarbeit zunimmt. Selbst wenn ich zum Beispiel glaube, dass die globalen Variablen global und nicht in einer Funktion definiert werden müssen, kann ich einen Standard verstehen, der sie in einer Funktion namens wird immer in der ersten Zeile der main()
one aufgerufen …
Unterschätzen Sie nicht zuletzt die Möglichkeit im modernen Quellcode Editoren zum Anzeigen oder Ausblenden selektiv getrennter Routinen ( Code-Faltung ). Dadurch bleibt der Code kompakt und der Benutzer kann erneut Zeit sparen.
Hier oben können Sie sehen, wie es entfaltet nur die Funktion walk_into_bar()
. Selbst wenn die anderen jeweils 1000 Zeilen lang waren, konnten Sie den gesamten Code auf einer einzigen Seite unter Kontrolle halten. Beachten Sie, dass es sogar in dem Abschnitt gefaltet ist, in dem Sie die Variablen deklarieren / initialisieren.
Antwort
Ein weiterer Grund das oft übersehen wird, ist die Syntaxanalyse von bash:
set -eu echo "this shouldn"t run" { echo "this shouldn"t run either"
Dieses Skript enthält offensichtlich einen Syntaxfehler und bash sollte es überhaupt nicht ausführen, oder? Falsch.
~ $ bash t1.sh this shouldn"t run t1.sh: line 7: syntax error: unexpected end of file
Wenn wir den Code in eine Funktion einbinden würden, würde dies nicht passieren:
set -eu main() { echo "this shouldn"t run" { echo "this shouldn"t run either" } main
~ $ bash t1.sh t1.sh: line 10: syntax error: unexpected end of file
Antwort
Abgesehen von den in anderen Antworten angegebenen Gründen:
- Psychologie: Ein Programmierer, dessen Produktivität in Codezeilen gemessen wird, hat einen Anreiz, unnötig ausführlichen Code zu schreiben. Je mehr Management vorhanden ist Je mehr Anreize der Programmierer hat, seinen Code mit unnötiger Komplexität zu erweitern, desto unerwünschter ist dies. Dies ist unerwünscht, da eine erhöhte Komplexität zu erhöhten Wartungskosten und einem erhöhten Aufwand für die Fehlerbehebung führen kann.
Kommentare
- Es ist keine so schlechte Antwort, wie die Abstimmungen sagen. Hinweis: agc sagt, auch dies ist eine Möglichkeit, und ja, das ist es. Er ‚ sagt nicht, dass dies die einzige Möglichkeit wäre, und ‚ beschuldigt niemanden, gibt nur die Fakten an. Obwohl ich denke, dass heute eine direkte “ Codezeile “ – > “ $$ “ Vertragsjob, auf indirekte Weise ist es durchaus üblich, dass ja, die Masse des produzierten Codes von den Führungskräften zählt / Chefs.
main
zu deklarieren?