GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum ruft popen() eine Shell auf, um einen Prozess auszuführen?

Die Version 2004 von POSIX system() Dokumentation hat eine Begründung, die wahrscheinlich auf popen() anwendbar ist auch. Beachten Sie die angegebenen Einschränkungen zu system() , insbesondere diejenige, die besagt, "dass die Prozess-ID anders ist":

BEGRÜNDUNG

...

Es gibt drei Spezifikationsebenen für die Funktion system(). Der ISO-C-Standard bietet die grundlegendsten. Es erfordert, dass die Funktion existiert, und definiert eine Möglichkeit für eine Anwendung, abzufragen, ob ein Befehlsspracheninterpreter existiert. Es sagt nichts über die Befehlssprache oder die Umgebung aus, in der der Befehl interpretiert wird.

IEEE Std 1003.1-2001 schränkt system() zusätzlich ein. Wenn ein Befehlsspracheninterpreter vorhanden ist, muss die Umgebung den Angaben von fork() und exec entsprechen. Dadurch wird beispielsweise sichergestellt, dass close-on-exec funktioniert, Dateisperren nicht vererbt werden und die Prozess-ID unterschiedlich ist. Es gibt auch den Rückgabewert von system() an, wenn die Befehlszeile ausgeführt werden kann, und gibt der Anwendung somit einige Informationen über den Abschlussstatus des Befehls.

Schließlich verlangt IEEE Std 1003.1-2001, dass der Befehl wie in der Shell-Befehlssprache interpretiert wird, die im Shell and Utilities-Band von IEEE Std 1003.1-2001 definiert ist.

Beachten Sie die mehrfachen Verweise auf den „ISO C Standard“. Die neueste Version des C-Standards erfordert, dass die Befehlszeichenfolge vom "Befehlsprozessor" des Systems verarbeitet wird:

7.22.4.8 Die system Funktion

Inhaltsangabe

#include <stdlib.h>
int system(const char *string);

Beschreibung

Wenn string ist ein Nullzeiger, der system Die Funktion bestimmt, ob die Hostumgebung über einen Befehlsprozessor verfügt. Wenn string kein Nullzeiger ist, der system Die Funktion übergibt den String, auf den string zeigt an diesen Befehlsprozessor, um in einer Weise ausgeführt zu werden, die die Implementierung dokumentieren muss; dies kann dann dazu führen, dass das Programm system aufruft sich nicht konform zu verhalten oder zu kündigen.

Rückgaben

Wenn das Argument ein Nullzeiger ist, wird der system Die Funktion gibt nur dann einen Wert ungleich Null zurück, wenn ein Befehlsprozessor verfügbar ist. Wenn das Argument kein Nullzeiger ist und der system Funktion zurückgibt, gibt sie einen implementierungsdefinierten Wert zurück.

Da der C-Standard erfordert, dass der "Befehlsprozessor" des Systems für system() verwendet wird Anruf, ich vermute, dass:

  1. Irgendwo gibt es eine Anforderung in POSIX, die popen() bindet zum system() Umsetzung.
  2. Es ist viel einfacher, den "Befehlsprozessor" vollständig wiederzuverwenden, da es auch erforderlich ist, dass er als separater Prozess ausgeführt wird.

Das ist also die oberflächliche Antwort, die zweimal entfernt wurde.


Durch das Aufrufen einer Shell können Sie alle Dinge tun, die Sie auch in einer Shell tun können. Zum Beispiel

FILE *fp = popen("ls *", "r");

ist mit popen() möglich (erweitert alle Dateien im aktuellen Verzeichnis).Vergleichen Sie es mit:

execvp("/bin/ls", (char *[]){"/bin/ls", "*", NULL});

Sie können ls nicht ausführen mit * als Argument, weil exec(2) interpretiert * wörtlich.

Ebenso können Pipes (| ), Umleitung (> , < , ...) etc. sind mit popen möglich .

Andernfalls gibt es keinen Grund, popen zu verwenden wenn Sie Shell nicht brauchen - es ist unnötig. Am Ende haben Sie einen zusätzlichen Shell-Prozess und alle Dinge, die in einer Shell schief gehen können, können in Ihrem Programm schief gehen (z. B. könnte der von Ihnen übergebene Befehl von der Shell falsch interpretiert werden und ein allgemeines Sicherheitsproblem). popen() ist so gestaltet. fork + exec Die Lösung ist sauberer, ohne die Probleme, die mit einer Shell verbunden sind.


Die glatte Antwort lautet, weil der POSIX-Standard ( http://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html ) dies vorschreibt. Oder besser gesagt, es sagt, dass es sich so verhalten soll, als ob das Befehlsargument zur Interpretation an /bin/sh übergeben wird.

Ich nehme also an, dass eine konforme Implementierung im Prinzip auch eine interne Bibliotheksfunktion haben könnte, die Shell-Befehle interpretieren würde, ohne einen separaten Shell-Prozess forken und ausführen zu müssen. Mir ist keine solche Implementierung bekannt, und ich vermute, dass es ziemlich schwierig wäre, alle Eckfälle richtig hinzubekommen.


Linux
  1. Was ist POSIX? Warum ist es für Linux/UNIX-Benutzer wichtig?

  2. Wie führe ich einen Befehl in der Shell aus, ohne ihn im Verlauf zu speichern? [Linux-Tipps]

  3. Warum erfordert „ls“ einen separaten Prozess zur Ausführung?

  4. Was bedeutet die Syntax |&in der Shell-Sprache?

  5. Warum fügt Strg + V nicht in Bash (Linux-Shell) ein?

So verwenden Sie den htop-Befehl, um Systemprozesse in Echtzeit zu überwachen

So führen Sie einen Shell-Befehl mit Python aus

So führen Sie Shell-Befehle über einen HTTP-Server aus

Wie führe ich einen Befehl in einem Shell-Skript aus?

Warum wiederholt mein Linux-System jeden Befehl, den ich eingebe?

Warum dauert die Ausführung des sudo-Befehls lange?