La versión 2004 de POSIX system()
la documentación tiene una razón que probablemente sea aplicable a popen()
también. Tenga en cuenta las restricciones establecidas en system()
, especialmente el que indica "que el ID del proceso es diferente":
FUNDAMENTO
...
Hay tres niveles de especificación para la función system(). El estándar ISO C da lo más básico. Requiere que la función exista y define una forma para que una aplicación consulte si existe un intérprete de lenguaje de comandos. No dice nada sobre el lenguaje de comandos o el entorno en el que se interpreta el comando.
IEEE Std 1003.1-2001 impone restricciones adicionales en system(). Requiere que si hay un intérprete de lenguaje de comandos, el entorno debe ser el especificado por fork() y exec. Esto asegura, por ejemplo, que close-on-exec funcione, que los bloqueos de archivos no se hereden y que el ID del proceso sea diferente. También especifica el valor de retorno de system() cuando se puede ejecutar la línea de comando, lo que brinda a la aplicación información sobre el estado de finalización del comando.
Finalmente, IEEE Std 1003.1-2001 requiere que el comando se interprete como en el lenguaje de comandos de shell definido en el volumen Shell and Utilities de IEEE Std 1003.1-2001.
Tenga en cuenta las múltiples referencias a la "Norma ISO C". La última versión del estándar C requiere que la cadena de comandos sea procesada por el "procesador de comandos" del sistema:
7.22.4.8 El system
función
Sinopsis
#include <stdlib.h>
int system(const char *string);
Descripción
Si string
es un puntero nulo, el system
La función determina si el entorno host tiene un procesador de comandos. Si string
no es un puntero nulo, el system
la función pasa la cadena a la que apunta string
a ese procesador de comandos para ser ejecutado de una manera que la implementación deberá documentar; esto podría causar que el programa llame a system
comportarse de manera no conforme o terminar.
Devoluciones
Si el argumento es un puntero nulo, el system
function devuelve un valor distinto de cero solo si hay un procesador de comandos disponible. Si el argumento no es un puntero nulo y system
función devuelve, devuelve un valor definido por la implementación.
Dado que el estándar C requiere que el "procesador de comandos" del sistema se use para el system()
llamada, sospecho que:
- En algún lugar hay un requisito en POSIX que vincula
popen()
alsystem()
implementación. - Es mucho más fácil simplemente reutilizar el "procesador de comandos" por completo, ya que también existe el requisito de ejecutarlo como un proceso separado.
Así que esta es la respuesta simplista eliminada dos veces.
Invocar un shell le permite hacer todas las cosas que puede hacer en un shell. Por ejemplo,
FILE *fp = popen("ls *", "r");
es posible con popen()
(expande todos los archivos en el directorio actual). Compárelo con:
execvp("/bin/ls", (char *[]){"/bin/ls", "*", NULL});
No puedes ejecutar ls
con *
como argumento porque exec(2)
interpretará *
literalmente.
Del mismo modo, las tuberías (|
), redirección (>
, <
, ...), etc., son posibles con popen
.
De lo contrario, no hay razón para usar popen
si no necesita shell, es innecesario. Terminará con un proceso de shell adicional y todas las cosas que pueden salir mal en un shell pueden salir mal en su programa (por ejemplo, el comando que pasa podría ser interpretado incorrectamente por el shell y un problema de seguridad común). popen()
está diseñado de esa manera. fork
+ exec
la solución es más limpia sin los problemas asociados con un caparazón.
La respuesta simplista es porque el estándar POSIX ( http://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html ) lo dice. O más bien, dice que debería comportarse como si el argumento del comando se pasara a /bin/sh para su interpretación.
Entonces, supongo que una implementación conforme podría, en principio, también tener alguna función de biblioteca interna que interpretaría los comandos de shell sin tener que bifurcar y ejecutar un proceso de shell separado. En realidad, no estoy al tanto de ninguna implementación de este tipo, y sospecho que corregir todos los casos de esquina sería bastante complicado.