Warum erfordert "ls" einen separaten Prozess zur Ausführung?

14

Warum ist lsfür die Ausführung ein separater Prozess erforderlich? Ich kenne den Grund, warum Befehle wie cdnicht mit dem Gabelmechanismus ausgeführt werden können, aber kann es schaden, wenn lssie ohne Gabeln ausgeführt werden?

Crisron
quelle
1
Obwohl lses sich um ein externes Programm handelt, echo *oder echo * .*(abhängig von den Shell-Optionen) Dateien ziemlich gut auflistet, ohne zu forken.
Gerrit
Dies ist noch besser: printf "% s \ n" *
Costa
Shell Vielfalt Anmerkung: tcsh eine builtin hat , ls-Fdie wie wirkt ls -F. Es ist da für die Effizienz. Man bekommt immer -Fwas normalerweise eine gute Idee ist. Wenn Sie andere Optionen angeben, wird der Befehl external weitergeleitet.

Antworten:

18

Die Antwort ist mehr oder weniger lseine externe ausführbare Datei. Sie können die Position anzeigen, indem Sie ausführen type -p ls.

Warum ist lsdie Shell dann nicht eingebaut? Nun, warum sollte es sein? Die Aufgabe einer Shell besteht nicht darin, jeden verfügbaren Befehl zu umfassen, sondern eine Umgebung bereitzustellen, in der sie ausgeführt werden kann. Einige moderne Schalen haben echo, printfund Konsorten als builtins, die nicht technisch builtins sein müssen, sind aber so aus Performance - Gründen gemacht , wenn sie wiederholt ausgeführt werden (vor allem in engen Schleifen). Ohne sie zu integrieren, müsste die Shell für jeden Aufruf einen neuen Prozess ausgeben und ausführen, was extrem langsam sein kann.

Um lseine externe ausführbare Datei auszuführen, muss mindestens eine der Systemaufrufe der exec-Familie ausgeführt werden. Sie könnten dies ohne Gabeln tun, aber es würde die primäre Shell ersetzen, die Sie verwenden. Sie können sehen, was in dieser Instanz passiert, indem Sie wie folgt vorgehen:

exec ls; echo "this never gets printed"

Da das Prozessabbild Ihrer Shell ersetzt wird, ist die aktuelle Shell danach nicht mehr erreichbar. Damit die Shell nach dem Ausführen von ls weiter ausgeführt werden kann, muss der Befehl in die Shell integriert werden.

Durch das Verzweigen kann ein Prozess ersetzt werden, der nicht Ihre primäre Shell ist, sodass Sie Ihre Shell anschließend weiter ausführen können.

Chris Down
quelle
1
Ich denke, er fragt sich, warum ls (1) kein integriertes Feature von Shells ist, und jemand müsste erklären, wie verschiedene Anbieter unterschiedliche Optionen für ls (1) haben und in der Lage sind, verschiedene Dinge aus dem Dateisystem usw. abzufragen die Höhen und Tiefen, die es mit sich bringt, wenn es in die Hülle eingebaut wird.
llua
@llua Ich habe einige Informationen über das, und die Ausnahmefälle echo, printfusw.
Chris Hinunter
Es ist nicht immer klar, warum manche Dinge eingebaut sind und andere nicht. Warum ist beispielsweise cdkeine externe ausführbare Datei?
Faheem Mitha
@FaheemMitha In POSIX-kompatiblen Betriebssystemen ist eine externe cdausführbare Datei vorhanden ( siehe hier ). Wenn Sie jedoch tatsächlich chdir () im aktuellen Prozess verwenden möchten, müssen Sie es in die Shell integrieren.
Chris Down
es ist zur Gewohnheit geworden, warum lses extern ist, aber es kann auch in einer Shell implementiert werden. Siehe busybox.
15

Im Bash-Referenzhandbuch heißt es:

Integrierte Befehle sind erforderlich, um Funktionen zu implementieren, die mit separaten Dienstprogrammen nicht oder nur schwer zu erhalten sind.

Das heißt, Shells enthalten nur dann eingebaute Befehle, wenn:

  1. Wird vom POSIX-Standard benötigt
  2. Befehle, die Zugriff auf die Shell selbst erfordern, z. B. integrierte Jobsteuerungsfunktionen
  3. Sehr einfache Befehle, die nicht vom Betriebssystem abhängig sind und die Ausführungseffizienz erhöhen, wenn sie als integrierte Befehle wie printf implementiert werden

Der lsBefehl entspricht keiner der oben genannten Anforderungen.

Allerdings , hier ist keine Programmierung Einschränkung , die verhindern würde lsals Einbau in wobei implmented, die sich im selben Prozess wie der Bash - Interpreter ausgeführt wird . Die Entwurfsgründe für Befehle, die nicht als Shell-Einbauten implementiert werden, sind:

  1. Die Shell sollte vom Dateisystem getrennt sein - keine eingebauten Befehle sollten vom korrekten Betrieb eines Dateisystems oder von Peripheriegeräten abhängen
  2. Ein Befehl, der vom Dateisystemtyp oder vom Betriebssystem abhängig sein kann, sollte eine separate ausführbare Datei sein
  3. Ein Befehl, zu dem oder von dem Sie eine Pipe ausführen möchten, sollte ein separater Prozess sein
  4. Ein Befehl, den Sie möglicherweise im Hintergrund ausführen möchten, sollte eine separate ausführbare Datei sein
  5. Ein Befehl mit einer großen Anzahl möglicher Parameter ist besser in einer separaten ausführbaren Datei zu implementieren
  6. Befehle, die unabhängig von der Art der Shell (bash, csh, tsh, ...) dieselbe Ausgabe haben sollten, sollten eigenständige ausführbare Dateien sein

Zum ersten Grund: Sie möchten, dass die Shell so unabhängig und widerstandsfähig wie möglich ist. Sie möchten nicht, dass die Shell an lseinem NFS-Mount hängen bleibt, der "immer noch nicht antwortet".

Zum zweiten Grund: In vielen Fällen möchten Sie möglicherweise eine Shell für ein System verwenden, das Busybox oder ein anderes Dateisystem mit einer anderen lsImplementierung verwendet. Oder verwenden Sie in Betriebssystemen mit unterschiedlichen lsImplementierungen dieselbe Shell-Quelle .

Zum dritten Grund - Für Ausdrücke wie find . -type d | xargs ls -ladwäre es schwierig oder unmöglich, die lsim gleichen Prozess wie der Shell-Interpreter zu implementieren .

Zum vierten Grund - Die lsAusführung einiger Befehle kann einige Zeit in Anspruch nehmen. Vielleicht möchten Sie, dass die Shell in der Zwischenzeit noch etwas anderes ausführt.


Hinweis: Siehe diesen hilfreichen Beitrag von Warren Young als Antwort auf eine ähnliche Frage.

Jonathan Ben-Avraham
quelle
Sie haben die einfache Weiterleitung der Ausgabe verpasst, wenn es sich um einen separaten Befehl handelt, und die gesamte Programmierung, die erforderlich ist, um ein Shell-Primitiv in eine separate ausführbare Datei weiterzuleiten.
Bruce Ediger
@BruceEdiger: Was für eine Freude, einen Kommentar von der geschätzten BE zu erhalten. Vielen Dank! Ich glaube, Grund 3 deckt Ihren Kommentar ab, nein?
Jonathan Ben-Avraham
1
Ich dachte eher daran, wie kompliziert der Quellcode der Shell selbst wäre, wenn er Pipes für externe Prozesse handhaben müsste, und die Ausgabe eines internen Befehls wie das Hypothetische lsin einen externen Prozess umleiten müsste . Es könnte getan werden, aber es wäre kompliziert.
Bruce Ediger
1
Ich fürchte, die meisten, wenn nicht alle deine 5 Punkte sind umstritten. 1: ls ist (hoffentlich) unabhängig von der Dateisystemimplementierung. Es liegt am Kernel, eine konsistente Schnittstelle zur Standardbibliothek und zu den Anwendungen bereitzustellen. 2: ls ist wahrscheinlich weniger vom Betriebssystem abhängig als die Shell. 3: Muscheln erlauben definitiv den Einbau in Rohrleitungen. 4: Mit Shells können Builtins definitiv im Hintergrund ausgeführt werden. 5: das ist ziemlich subjektiv.
Juli
1
@ JonathanBen-Avraham @BruceEdiger Behandeln Schalen nicht bereits das Rohrgehäuse für Einbauten mit Unterschalen? zB bashAusgabe alias | grep ls. Eingabecat /etc/passwd | while read a; do echo "$a"; done
Matt
2

lserfordert keinen separaten Prozess. Nur sehr wenige Befehle erfordern einen separaten Prozess: Nur diejenigen, die Berechtigungen ändern müssen.

In der Regel implementieren Shells Befehle nur dann als integrierte Befehle, wenn diese Befehle als integrierte Befehle implementiert werden müssen. Befehle wie alias, cd, exit, export, jobs, ... muß einigen internen Zustand der Schale lesen oder zu ändern, und kann daher nicht getrennte Programme sein. Befehle ohne solche Anforderungen können separate Befehle sein. Auf diese Weise können sie von jeder Shell oder einem anderen Programm aus aufgerufen werden.

Betrachtet man die Liste der Buildins in Bash, so können nur die folgenden Buildins als separate Befehle implementiert werden. Für einige von ihnen würde es einen leichten Funktionsverlust geben.

  • command- aber es würde seine Nützlichkeit in Situationen verlieren, in denen es PATHmöglicherweise nicht richtig eingerichtet ist und das Skript es commandals Teil der Einrichtung verwendet.
  • echo - Es ist ein fester Bestandteil der Effizienz.
  • help - Es könnte eine separate Datenbank verwendet werden, aber das Einbetten des Hilfetexts in die ausführbare Shell-Datei hat den Vorteil, dass die ausführbare Shell in sich geschlossen ist.
  • kill - Ein integrierter Prozess bietet zwei Vorteile: Er kann neben Prozess-IDs auch Job-Bezeichnungen erkennen und verwendet werden, selbst wenn nicht genügend Ressourcen zum Starten eines separaten Prozesses vorhanden sind.
  • printf- Aus dem gleichen Grund wie echound um die -vOption zu unterstützen, die Ausgabe in eine Variable zu setzen.
  • pwd - Das eingebaute Modul bietet die zusätzliche Möglichkeit, das aktuelle Verzeichnis logisch zu verfolgen (wobei symbolische Verknüpfungen intakt bleiben, anstatt sie zu erweitern).
  • test- Es ist aus Effizienzgründen eingebaut (und Bash macht auch etwas Magie mit Dateien, die /dev/fd/…auf einigen Betriebssystemen aufgerufen werden).

Einige wenige Muscheln bieten eine erhebliche Anzahl zusätzlicher eingebauter Komponenten. Es gibt Sash , eine Shell, die als eigenständige Binärdatei für Notfallreparaturen entwickelt wurde (wenn einige externe Befehle möglicherweise nicht verwendet werden können). Es hat ein eingebautes ls, genanntes -ls, sowie andere Tools wie -grepund -tar. Die eingebauten Funktionen von Sash sind weniger leistungsfähig als die vollwertigen Befehle. Zsh bietet einige ähnliche integrierte Funktionen in seinem Modul zsh / files an . Es hat keine ls, aber Wildcard-Erweiterung ( echo *) und zstatkann eine ähnliche Funktion erfüllen.

Gilles 'SO - hör auf böse zu sein'
quelle
2

Ich denke, dass hier etwas fehlt, was die Scherkomplexität des GNU- lsProgramms unter Linux ist. Vergleicht man die ausführbare Größe von lsmit bashund dashShells auf meinem Debian-System, so sieht man, dass es ziemlich groß ist:

graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30  2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls

Das Einbeziehen einer lsso umfassenden Version wie die GNU-Version in bashwürde die ausführbare Größe um 10% erhöhen. Es ist fast so groß wie die ganze dashSchale!

Die meisten Shell-Buildins werden ausgewählt, weil sie sich so in die Shell integrieren lassen, wie es externe ausführbare Dateien nicht können (die Frage zeigt cd, aber ein anderes Beispiel ist die Bash-Version der killIntegration in die Bash-Job-Steuerung) oder weil sie sehr einfach zu implementierende Befehle sind. eine große Geschwindigkeit gegen Größe auszahlen ( trueund falsesind so einfach wie es nur geht).

GNU lshatte einen langen Entwicklungszyklus und implementiert möglicherweise Optionen, um anzupassen, welche / wie Ergebnisse angezeigt werden. Die Verwendung eines integrierten Betriebssystems würde entweder diese Funktionalität verlieren oder die Komplexität und Größe der Shell erheblich erhöhen.

Graeme
quelle
1

cdist in die Shell eingebaut, lsist ein separates Programm, das Sie bei sehen werden /bin/ls.

DopeGhoti
quelle
0

Das tun, wonach Sie suchen:

printf "%s\n" *

Sie können auch Dateinamen im Array speichern:

files=(`printf "%s\n" *`)  #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done

Leerzeichen in Namen sind ihm jedoch egal.
Dies wird an Variable übergeben und Leerzeichen sind wichtig:

printf "%s\n" * | while read a; do echo $a; done
Costa
quelle