2008-09-16 24 views
7

¿Cómo debo ejecutar otro programa desde mi programa C? Necesito poder escribir datos en STDIN del programa lanzado (y quizás leer en STDOUT)Ejecutar programa desde dentro de un programa C

No estoy seguro si esta es una función C estándar. Necesito la solución que debería funcionar bajo Linux.

+0

Este es un duplicado de esta pregunta: http://stackoverflow.com/questions/17140/how-do-you-spawn-another-process-in-c –

Respuesta

17

Quiere usar popen. Le proporciona una tubería unidireccional con la que puede acceder a stdin y stdout del programa.

popen es estándar en los modernos sistema operativo UNIX y similares, de los cuales Linux es uno :-)

Tipo

man popen 

en un terminal para leer mas sobre esto.

EDITAR

Si popen produce tubos unidireccional o bidireccional depende de la aplicación. En Linux y OpenBSD, popen produce tubos unidireccionales, que son de solo lectura o de solo escritura. En OS X, FreeBSD y NetBSDpopen produce tubos bidireccionales.

+1

Tenga en cuenta que es stdin _or_ stdout, no ambos a la vez. – wnoise

+0

En implementaciones modernas, es stdin AND stdout. La tubería puede ser bidireccional, aunque tradicionalmente es unidireccional. – freespace

+0

"man popen" en Ubuntu 9.04 dice "Como una tubería es, por definición, unidireccional, el argumento tipo puede especificar solo lectura o escritura, no ambas". – nobar

0

Creo que se puede utilizar

freopen

para esto.

7
  1. Cree dos tubos con pipe(...), uno para stdin, uno para stdout.
  2. fork(...) el proceso.
  3. En el proceso secundario (aquel en el que fork(...) devuelve 0) dup (...) las tuberías a stdin/stdout.
  4. exec[v][e] el archivo de programa por iniciar en el proceso secundario.
  5. En el proceso padre (el uno donde fork) devuelve el PID del niño) hacer un bucle que lee de, de stdout (select(...) o poll(...), read(...)) en un tampón de niño, hasta que el niño termina (waitpid(...)).
  6. Suministre eventualmente al niño con entrada en stdin si espera algo.
  7. Cuando termine close(...) las tuberías.
4

no estoy de acuerdo con Nathan Fellman - la otra pregunta no es un duplicado de éste, aunque el tema está relacionado.

Para una comunicación unidireccional simple, popen() es una solución decente. Sin embargo, no sirve para la comunicación bidireccional.

IMO, imjorge (Jorge Ferreira) dio la mayor parte de la respuesta (80%?) Para la comunicación bidireccional, pero omitió algunos detalles clave.

  1. Es crucial que el proceso primario cierre el extremo de lectura de la tubería que se utiliza para enviar mensajes al proceso hijo.
  2. Es crucial que el proceso secundario cierre el extremo de escritura de la tubería que se utiliza para enviar mensajes al proceso secundario.
  3. Es crucial que el proceso primario cierre el final de escritura del conducto que se utiliza para enviar mensajes al proceso padre.
  4. Es crucial que el proceso secundario cierre el extremo de lectura de la tubería que se utiliza para enviar mensajes al proceso primario.

Si no cierra los extremos no utilizados de las tuberías, no obtendrá un comportamiento razonable cuando termine uno de los programas; por ejemplo, el niño podría estar leyendo desde su entrada estándar, pero a menos que el extremo de escritura de la tubería esté cerrado en el niño, nunca obtendrá EOF (cero bytes de lectura) porque todavía tiene la tubería abierta y el sistema piensa que En algún momento podría escribir sobre ese tubo, aunque actualmente esté colgado esperando que se lea algo de él.

Los procesos de escritura deben considerar si se debe manejar la señal SIGPIPE que se proporciona al escribir en una tubería donde no hay proceso de lectura.

Debe tener en cuenta la capacidad de la tubería (depende de la plataforma, y ​​puede ser tan poco como 4 KB) y diseñar los programas para evitar el interbloqueo.

8

Escribí un ejemplo de código C para otra persona hace un tiempo que muestra cómo hacerlo. Aquí es para usted:

#include <sys/types.h> 
#include <unistd.h> 
#include <stdio.h> 

void error(char *s); 
char *data = "Some input data\n"; 

main() 
{ 
    int in[2], out[2], n, pid; 
    char buf[255]; 

    /* In a pipe, xx[0] is for reading, xx[1] is for writing */ 
    if (pipe(in) < 0) error("pipe in"); 
    if (pipe(out) < 0) error("pipe out"); 

    if ((pid=fork()) == 0) { 
    /* This is the child process */ 

    /* Close stdin, stdout, stderr */ 
    close(0); 
    close(1); 
    close(2); 
    /* make our pipes, our new stdin,stdout and stderr */ 
    dup2(in[0],0); 
    dup2(out[1],1); 
    dup2(out[1],2); 

    /* Close the other ends of the pipes that the parent will use, because if 
    * we leave these open in the child, the child/parent will not get an EOF 
    * when the parent/child closes their end of the pipe. 
    */ 
    close(in[1]); 
    close(out[0]); 

    /* Over-write the child process with the hexdump binary */ 
    execl("/usr/bin/hexdump", "hexdump", "-C", (char *)NULL); 
    error("Could not exec hexdump"); 
    } 

    printf("Spawned 'hexdump -C' as a child process at pid %d\n", pid); 

    /* This is the parent process */ 
    /* Close the pipe ends that the child uses to read from/write to so 
    * the when we close the others, an EOF will be transmitted properly. 
    */ 
    close(in[0]); 
    close(out[1]); 

    printf("<- %s", data); 
    /* Write some data to the childs input */ 
    write(in[1], data, strlen(data)); 

    /* Because of the small amount of data, the child may block unless we 
    * close it's input stream. This sends an EOF to the child on it's 
    * stdin. 
    */ 
    close(in[1]); 

    /* Read back any output */ 
    n = read(out[0], buf, 250); 
    buf[n] = 0; 
    printf("-> %s",buf); 
    exit(0); 
} 

void error(char *s) 
{ 
    perror(s); 
    exit(1); 
} 
Cuestiones relacionadas