La version 2004 du POSIX system()
la documentation a une justification qui s'applique probablement à popen()
aussi bien. Notez les restrictions indiquées sur system()
, en particulier celui indiquant "que l'ID de processus est différent" :
JUSTIFICATION
...
Il existe trois niveaux de spécification pour la fonction system(). La norme ISO C donne les plus élémentaires. Il nécessite que la fonction existe et définit un moyen pour une application de demander si un interpréteur de langage de commande existe. Il ne dit rien sur le langage de commande ou l'environnement dans lequel la commande est interprétée.
IEEE Std 1003.1-2001 impose des restrictions supplémentaires sur system(). Il nécessite que s'il existe un interpréteur de langage de commande, l'environnement doit être tel que spécifié par fork() et exec. Cela garantit, par exemple, que la fermeture à l'exécution fonctionne, que les verrous de fichiers ne sont pas hérités et que l'ID de processus est différent. Il spécifie également la valeur de retour de system() lorsque la ligne de commande peut être exécutée, donnant ainsi à l'application des informations sur l'état d'achèvement de la commande.
Enfin, IEEE Std 1003.1-2001 exige que la commande soit interprétée comme dans le langage de commande shell défini dans le volume Shell and Utilities de IEEE Std 1003.1-2001.
Notez les multiples références à la "norme ISO C". La dernière version de la norme C exige que la chaîne de commande soit traitée par le "processeur de commande" du système :
7.22.4.8 Le
system
fonctionSynopsis
#include <stdlib.h> int system(const char *string);
Description
Si
string
est un pointeur nul, lesystem
La fonction détermine si l'environnement hôte dispose d'un processeur de commande. Sistring
n'est pas un pointeur nul, lesystem
la fonction passe la chaîne pointée parstring
à ce processeur de commandes à exécuter d'une manière que la mise en œuvre doit documenter ; cela pourrait alors amener le programme à appelersystem
de se comporter de manière non conforme ou de résilier.Retours
Si l'argument est un pointeur nul, le
system
la fonction renvoie une valeur différente de zéro uniquement si un processeur de commandes est disponible. Si l'argument n'est pas un pointeur nul et que lesystem
fonction renvoie, elle renvoie une valeur définie par l'implémentation.
Étant donné que la norme C exige que le "processeur de commandes" du système soit utilisé pour le system()
appeler, je soupçonne que :
- Quelque part, il y a une exigence dans POSIX qui lie
popen()
ausystem()
mise en œuvre. - Il est beaucoup plus simple de réutiliser entièrement le "processeur de commandes", car il est également nécessaire de l'exécuter en tant que processus distinct.
C'est donc la réponse désinvolte supprimée deux fois.
L'invocation d'un shell vous permet de faire tout ce que vous pouvez faire dans un shell. Par exemple,
FILE *fp = popen("ls *", "r");
est possible avec popen()
(développe tous les fichiers du répertoire courant). Comparez-le avec :
execvp("/bin/ls", (char *[]){"/bin/ls", "*", NULL});
Vous ne pouvez pas exécuter ls
avec *
comme argument car exec(2)
interprétera *
littéralement.
De même, les pipes (|
), redirection (>
, <
, ...), etc., sont possibles avec popen
.
Sinon, il n'y a aucune raison d'utiliser popen
si vous n'avez pas besoin de shell - c'est inutile. Vous vous retrouverez avec un processus shell supplémentaire et toutes les choses qui peuvent mal tourner dans un shell go peuvent mal tourner dans votre programme (par exemple, la commande que vous passez peut être mal interprétée par le shell et un problème de sécurité courant). popen()
est conçu ainsi. fork
+ exec
la solution est plus propre sans les problèmes associés à un shell.
La réponse désinvolte est parce que la norme POSIX ( http://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html ) le dit. Ou plutôt, il dit qu'il doit se comporter comme si l'argument de la commande était passé à /bin/sh pour interprétation.
Je suppose donc qu'une implémentation conforme pourrait, en principe, avoir également une fonction de bibliothèque interne qui interpréterait les commandes shell sans avoir à bifurquer et à exécuter un processus shell séparé. Je ne suis pas au courant d'une telle implémentation, et je pense qu'il serait assez difficile de corriger tous les cas particuliers.