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:
- Irgendwo gibt es eine Anforderung in POSIX, die
popen()
bindet zumsystem()
Umsetzung. - 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.