Ich habe viele Antworten und Kommentare zu Stack Overflow gesehen das Erwähnen etwas zu tun, um eine Subshell zu vermeiden. In einigen Fälle, ist ein funktioneller Grund dafür gegeben (Meistens, die potentielle Notwendigkeit, eine Variable zu lesen außerhalb der Subshell, die in ihm zugewiesen wurde), aber in In anderen Fällen scheint die Vermeidung als ein Ende gesehen zu werden in sich selbst. Zum Beispiel
Vereinigung von zwei Spalten einer tsv-Datei
schlägt { ... ; } | ...
eher vor als
( ... ) | ...
, es gibt also eine Subshell.
versteckte Dateien in Unix mit den Befehlen sed und mv anzeigen
Linux-Bash-Skript zum Kopieren von Dateien explizit angeben, "Das Ziel ist nur eine Subshell zu vermeiden"
Warum ist das? Ist es für Stil / Eleganz / Schönheit? Zum Leistung (Vermeidung einer Gabelung)? Zur Verhinderung wahrscheinlich Fehler? Etwas anderes?
Es gibt ein paar Dinge.
Erstens kann das Umzweigen einer Subshell unbemerkbar sein, wenn es nur einmal passiert, aber wenn Sie es in einer Schleife tun, ergibt dies eine messbare Auswirkung auf die Performance. Auch auf Plattformen wie Windows, wo Forking nicht so billig ist wie auf modernen Unixlikes, ist der Performance-Effekt größer.
Zweitens bedeutet das Forking einer Subshell, dass Sie mehr als einen Kontext haben und Informationen beim Wechsel zwischen ihnen verloren gehen. Wenn Sie Ihren Code ändern, um eine Variable in einer Subshell festzulegen, geht diese Variable verloren, wenn die Subshell beendet wird. Je mehr Code also Subshells enthält, desto sorgfältiger müssen Sie sein, wenn Sie später Änderungen vornehmen, um sicherzustellen, dass alle von Ihnen vorgenommenen Statusänderungen tatsächlich bestehen bleiben.
Siehe BashFAQ # 24 für einige Beispiele für überraschendes Verhalten, das durch Subshells verursacht wird.
Manchmal sind Beispiele hilfreich.
%Vor%Wie Sie sehen können, liegt der Unterschied zwischen der Verwendung von grep in einer Subshell und der Parametererweiterung für den gleichen Basistest in der Gesamtzeit bei etwa 100x.
Im Anschluss an die Frage und unter Berücksichtigung der nachstehenden Kommentare, die eindeutig nicht angeben, was sie angeben möchten, habe ich den folgenden Code überprüft: Ссылка
%Vor%Das ist eigentlich viel schlimmer als ich erwartet habe. Fast zwei Größenordnungen langsamer in der Gesamtzeit und fast drei Größenordnungen langsamer in der Sys-Call-Zeit, was absolut unglaublich ist. Ссылка
Beachten Sie, dass der Beweis dafür ist, dass Sie, wenn Sie eine Testmethode verwenden, die sich leicht in die Angewohnheit der Verwendung von subshell grep oder sed oder gawk (oder eines bash butintin, wie echo) einfügt, Das ist für mich eine schlechte Angewohnheit, in die ich beim schnellen Hacken stolpere, es ist wert zu erkennen, dass dies einen signifikanten Leistungseinbruch haben wird, und es ist wahrscheinlich die Zeit wert, diese zu meiden, wenn Bash-Builtins den Job nativ verarbeiten können.
Durch sorgfältige Überprüfung der Verwendung von Subshells für große Programme und deren Ersatz durch andere Methoden konnte ich nach einer gerade abgeschlossenen Optimierungsreihe etwa 10% der gesamten Ausführungszeit reduzieren (nicht die erste und nicht die erste) die letzte, Zeit, die ich das getan habe, wurde bereits mehrmals optimiert, so dass das Gewinnen von weiteren 10% tatsächlich ziemlich bedeutend ist)
Es ist also wert, sich dessen bewusst zu sein.
Weil ich neugierig war, wollte ich bestätigen, was "Zeit" uns hier sagt: Ссылка
Die Gesamt-CPU-Zeit ist die Kombination aus der Zeit, die die CPU oder die CPU benötigt CPUs haben einige Aktionen für ein Programm und die Zeitdauer ausgeführt Sie haben Systemaufrufe für den Kernel auf dem Programm ausgeführt Namen. Wenn ein Programm ein Array durchläuft, akkumuliert es den Benutzer CPU-Zeit Umgekehrt, wenn ein Programm einen Systemaufruf wie z exec oder fork, akkumuliert die System-CPU-Zeit.
Wie Sie besonders im Echo-Loop-Test sehen können, sind die Kosten für die Gabeln in Bezug auf Systemaufrufe an den Kernel sehr hoch, diese Gabeln addieren sich wirklich (700x !!! mehr Zeit für sys-Aufrufe).
Ich bin dabei, einige dieser Probleme zu lösen, daher sind diese Fragen für mich und die globale Gemeinschaft von Benutzern, die das fragliche Programm mögen, ziemlich relevant, das heißt, es handelt sich nicht um einen obskuren akademischen Punkt Für mich ist es eine reale Welt mit echten Auswirkungen.
Nun, hier ist meine Interpretation, warum das wichtig ist: Es ist Antwort # 2!
es gibt keinen kleinen Leistungszuwachs, auch wenn es darum geht, eine Subshell zu vermeiden ... Nennt mich Mr Obvious, aber das Konzept hinter diesem Denken ist dasselbe, das dahinter steht, die nutzlose Verwendung von <insert tool here>
like cat|grep
, sort|uniq
oder gar zu vermeiden cat|sort|uniq
etc ..
Dieses Konzept ist die Unix-Philosophie , die ESR summiert sich gut durch einen Verweis auf KISS : Behalte es einfach, dumm!
Was ich meine ist, dass wenn Sie ein Skript schreiben, Sie nie wissen, wie es am Ende verwendet werden kann, also ist jedes kleine Byte oder jeder Zyklus, den Sie sparen können, wichtig, wenn Ihr Skript Milliarden von Inputzeilen isst , dann werden viele Gabeln / Bytes / ... optimiert.
Ich denke, die allgemeine Idee ist, dass es sinnvoll ist, die Erstellung eines zusätzlichen Shell-Prozesses zu vermeiden, sofern nicht anders erforderlich.
Es gibt jedoch zu viele Situationen, in denen eine verwendet werden kann und die eine sinnvoller ist als die andere, dass eine Methode insgesamt besser ist als die andere. Es scheint mir rein situativ zu sein.