Darf die Shell nutzlose Abbruchbefehle optimieren?


27

Wenn eine Shell aufgefordert wird, einen wahrscheinlich unbrauchbaren ( oder teilweise unbrauchbaren ) Befehl auszuführen, von dem bekannt ist, dass er beendet wird, wie z. B. cat hugeregularfile.txt > /dev/null, kann sie die Ausführung dieses Befehls überspringen ( oder eine billigere Entsprechung ausführen , z. B. touch -a hugeregularfile.txt)?

Im Allgemeinen ähnelt die Shell C-Compilern dahingehend, dass sie den Quellcode umwandeln kann, solange das von außen beobachtbare Verhalten so ist, als ob es von der abstrakten Maschine ausgewertet würde.

BEARBEITEN

Nota Bene: Meine Frage , wie ursprünglich gestellt hatte einen Titel, der Frage , ob die Schale erlaubt diese Optimierungen zu tun, nicht , ob es sein sollte oder ob Implementierungen , die sie existieren tun können. Ich interessiere mich mehr für die Theorie als für die Praxis, obwohl beide willkommen sind.


Nein, die Shell ist nicht so schlau wie moderne Compiler. Tatsächlich ist es ziemlich dumm. Es würde keinen nutzlosen Code optimieren.
Devnull

12
Die Shell sollte nicht raten, was der Benutzer beabsichtigt. Der Benutzer könnte versuchen, fast alles mit diesem Befehl zu tun. Es wäre falsch, ihn zu optimieren, selbst wenn dies möglich wäre.
Chris Down

1
Egal, ob es sich bei der Datei um ein Gerät handelte oder nicht, cates macht einen großen Unterschied. Die Shell kann erkennen, dass die Datei ein Gerät ist, sie muss jedoch nicht zuverlässig sein.
Du

3
@StephaneChazelas C-Compiler müssen nicht "um Erlaubnis von jemandem bitten", um ihre kompilierten Programme zu optimieren. Es gibt eine Als-ob- Regel im C-Standard, die es ihnen erlaubt. Der POSIX-Standard scheint mindestens eine Shell ( pubs.opengroup.org/onlinepubs/009695399/utilities/… ) sowie zahlreiche andere Dienstprogramme ( pubs.opengroup.org/onlinepubs/009604499/utilities/wc.html for standardisiert zu haben wc, zum Beispiel). Nach meinem besten Wissen bezieht POSIX jedoch keine Position in Bezug auf die Shell-Optimierung. Oder doch?
Ich werde nicht existieren Idonotexist

2
Durch die Optimierung wird die Leistung mit Verknüpfungen verbessert, ohne die Funktionalität zu beeinträchtigen. Solange die Funktionalität garantiert ist, kann ich keine POSIX-Einwände sehen. Ihre vorgeschlagene Optimierung würde jedoch die Katzenspezifikation sprengen . In der POSIX-Spezifikation gibt es spezielle Formulierungen, die der Art der von vorgenommenen Optimierung entsprechen ksh. Wie sie sagen, nicht separate Prozesse, sondern Subshell-Umgebungen , um gabelsparende Optimierungen zu ermöglichen.
Stéphane Chazelas

Antworten:


26

Nein, das wäre eine schlechte Idee.

cat hugeregularfile.txt > /dev/nullund touch -a hugeregularfile.txtsind nicht dasselbe. catliest die gesamte Datei, auch wenn Sie die Ausgabe an umleiten /dev/null. Und das Lesen der gesamten Datei könnte genau das sein, was Sie wollen. Zum Beispiel, um es zwischenzuspeichern, so dass spätere Lesevorgänge bedeutend schneller sind. Die Shell kann Ihre Absicht nicht erkennen.

Ebenso optimiert ein C-Compiler das Lesen einer Datei nie, selbst wenn Sie sich die gelesenen Inhalte nicht ansehen.


2
@Iwillnotexist: Jeder nützliche Befehl (außer fraglich trueund false) hat potenzielle Nebenwirkungen, und die Nebenwirkungen sind fast immer der Punkt, an dem der Befehl aufgerufen wird . Die Shell konnte diese Nebenwirkungen nicht im Voraus kennen (für externe Programme wie cat), ohne das Halteproblem zu lösen. Also versucht es das zu Recht nicht und geht davon aus, dass Sie gemeint haben, was Sie gesagt haben.
CHAO

5
@IwillnotexistIdonotexist Nein, die Shell kann nicht sehen, was gerade passiert. Es hat keine Ahnung von cat. In der Tat catkönnte alles von der Formatierung Ihrer Festplatte bis zum Herunterladen des Internets getan werden.
Scai

5
"Unix sollte seine Benutzer nicht davon abhalten, dumme Dinge zu tun, da dies sie auch davon abhalten würde, kluge Dinge zu tun." - Doug Gwyn
Agi Hammerthief

7
@cHao Und eben trueund falseeingestellt $?.
Kyle Strand

3
Wie @scai oben ausgeführt, ausführbare Dateien sind nicht wie die Sprache Schlüsselwörter: catund /dev/nullhaben typische Bedeutungen , aber sie sind nicht garantiert verhalten , dass die Art und Weise. Um Optimierungen durchzuführen und gleichzeitig sicherzustellen, dass sich das erwartete Verhalten nicht ändert, kann die Optimierung nur mit Konstrukten durchgeführt werden, die in der Shell selbst implementiert sind, und nicht mit Dingen, die in der Ausführungsumgebung zu finden sind.
andybuckley

20

Nein, da /dev/nulles sich nur um einen Namen handelt, der für jedes andere Gerät oder für eine andere Datei als eine "normale" Datensenke verwendet werden kann.

Eine Shell (oder ein anderes Programm) hat aufgrund des Namens keine Ahnung, ob die Datei, in die sie schreibt, tatsächlich etwas mit den Daten tut. Es gibt bei AFAIK auch keine Systemaufrufe, die das Shell-Programm machen kann, um festzustellen, dass zB der Dateideskriptor eigentlich nichts tut.

Ihr Vergleich mit dem Optimieren von entferntem Code in einem C-Programm funktioniert nicht, da eine Shell nicht den Gesamtüberblick hat, den ein C-Compiler über einen Teil des Quellcodes hat. Eine Shell weiß nicht genug über /dev/nulldie Optimierung Ihres Beispiels, eher wie ein C-Compiler nicht genug über den Code in einem Funktionsaufruf, mit dem sie dynamisch verknüpft ist, um den Aufruf nicht auszuführen.


4
Wie sich herausstellt, wird ksh93 /dev/nullmanchmal speziell behandeln . Ein Builtin, dessen Standardausgabe /dev/nullz. B. an gerichtet ist echo foo >/dev/null, führt nicht dazu, dass Schreibvorgänge ausgeführt werden /dev/null. Es macht nichts Besonderes, wenn es einen nicht eingebauten Befehl (wie cat file >/dev/null) aufruft .
Mark Plotnick

Tatsächlich catkönnte es auch etwas anderes sein. Alles andere in der Tat.
Orion

3
Eigentlich /dev/nullist einer der wenigen standardisierten Wege , zusammen mit /dev/tty, /dev/console, /tmp, /dev/und /.
Gilles 'SO - hör auf böse zu sein'

2
@MarkPlotnick Eigentlich cat ist ein ksh93 eingebaut (nicht aktiviert, es sei denn, Sie setzen /opt/ast/binvorher /bin(oder wo immer welche catverfügbar sind) in $PATH). Und ja, obwohl cat file > /dev/nulldas eingebaute Programm readden Inhalt von ausführt, schreibt filees ihn nicht nach / dev / null (obwohl es geöffnet und gestartet wird).
Stéphane Chazelas

14

Laufende Befehle werden nicht optimiert (und Sie haben bereits eine Reihe guter Antworten erhalten, in denen erklärt wird, warum dies nicht der Fall sein sollte). In einigen Fällen werden jedoch möglicherweise Gabeln, Pipe- / Socket-Paare und Lesevorgänge optimiert. Welche Optimierungen es machen kann:

  • Bei den meisten modernen Shells wird der letzte Befehl in einem Skript im Allgemeinen im Verlauf der Shell ausgeführt, sofern nicht einige traps festgelegt wurden. Zum Beispiel in den sh -c lsmeist shImplementierungen ( bash, mksh, ksh, zsh, yash, einige Versionen von ash) nicht , ein Verfahren zur Lauf gabeln ls.
  • In ksh93wird durch die Befehlssubstitution erst dann ein Pipe- oder Fork- Prozess erstellt, wenn ein externer Befehl aufgerufen wird ( $(echo foo)beispielsweise fooohne Pipe / Socket-Paar oder Fork).
  • Die readeingebauten Shells ( bash, AT & T ksh) führen keine Einzelbyte-Lesevorgänge durch, wenn sie feststellen, dass stdin suchbar ist (in diesem Fall führen sie große Lesevorgänge durch und suchen bis zum Ende des Lesevorgangs zurück).

Ich mag diese Antwort, aber es ist unklar, ob dies der ursprüngliche Grund ist oder ob die Informationen aus einer Referenz stammen (auf die ich gerne
eingehen

3
@yoniYalovitsky, das ist der ursprüngliche Grund . ksh93Ist die Shell führend bei der Optimierung, da das Ziel / die Aufgabe darin bestand, Programmiersprachen wie perl. Sie können sich also die kshDokumentation, den Code (viel Glück) und die Mailingliste ansehen , um weitere Informationen zu erhalten.
Stéphane Chazelas

1
@HenkLangeveld, ja, Sie können überprüfen, mit sh -c 'ps -p "$$"'was Sie geben psund nicht shmit diesen shImplementierungen oder mit strace / truss / tusc ...
Stéphane Chazelas

1
Der Unterschied zwischen ksh -c 'ps; ps'und bash -c 'ps; ps' ist interessant. Ksh93 geht in seiner Optimierung weiter.
Henk Langeveld

1
@HenkLangeveld, hängt davon ab, von welcher Implementierung kshhier die Rede ist. mkshbenimmt sich wie bash. Dieses Verhalten ist hauptsächlich dazu gedacht, Dinge wie zu optimieren system("some command"). Beachten Sie, dass diese Optimierung einen Nebeneffekt hat, wenn es um den Beendigungsstatus von Prozessen geht, die durch ein Signal (in einigen Shells) beendet werden. ksh93Früher hatte es den Fehler, dass es die Optimierung selbst dann durchführte, wenn Traps gesetzt waren.
Stéphane Chazelas

7

Beim Sehen cat hugeregularfile.txt > /dev/nulldarf die Shell nicht glauben, dass die Aktion nutzlos ist - sie catist kein Teil der Shell und kann theoretisch und auch praktisch alles Mögliche tun.

Beispielsweise kann der Benutzer die ausführbare Datei rmin umbenannt haben cat, und die Zeile führt plötzlich ein extern beobachtbares Verhalten aus, dh das Entfernen der Datei.

Der Benutzer hat möglicherweise eine Version kompiliert cat, die in eine Endlosschleife übergeht. Daher kann die Shell nicht davon ausgehen, dass bekannt ist, dass sie beendet wird, wie Sie vorschlagen.

Jemand hat möglicherweise eine Version davon installiert cat, die wie beabsichtigt funktioniert, aber mit dem zusätzlichen Nebeneffekt, dass ein Rootkit installiert wird, falls es jemals mit angemessenen Berechtigungen ausgeführt wird. Auch hier sollte die Shell dies ordnungsgemäß ausführen.


2
mkshTatsächlich optimiert V=$(cat file)es tatsächlich, indem es ein eingebautes macht. Die Shell kann es also optimieren, aber nicht nur in a umwandelntouch -a .
Steve Schnepp

1
@SteveSchnepp, cat ist ein builtin in mksh, aber das builtin Resorts auf das System ist , catwenn eine Option übergeben, weshalb mit GNU ist cat, mksh -c 'cat /dev/null --help'führt nicht das gleiche Ergebnis wie bash -c 'cat /dev/null --help', aber mksh -c 'cat --help /dev/null'Ihnen nicht gibt das gleiche wie bash -c 'cat --help /dev/null'(wie mkshcat builtin Parsen Optionen die POSIX Art und Weise, während GNU cat sie auf die GNU-Art und Weise analysiert).
Stéphane Chazelas

In bash und ksh93 V=$(cat file)kann das mit optimiert werden V=$(< file). Dies beschleunigt die Dinge auch ohne eingebautes cat.
Henk Langeveld
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.