2011-12-08 37 views

Respuesta

6

execvpreemplaza el proceso de ejecución actual en memoria. No hay "captura" de la salida.

Sospecho que está intentando ejecutar un proceso externo desde un proceso existente y analizar su resultado. Para eso necesita usar popen() que hace un fork() luego un exec(), devolviendo un FILE * para leer (que será el stdout del proceso que acaba de ejecutar).

1

Consulte la documentación de popen, creo que es exactamente lo que necesita.

1

Como han dicho otros, popen es lo que desea utilizar. Algo como esto ...

#include <iomanip> 
#include <iostream> 

using namespace std; 

const int MAX_BUFFER = 255; 

int main() 
{ 
     string cmd; 
     cout << "enter cmd: "; 
     cin >> cmd; 
     cout << endl << "running " << cmd << "…" << endl; 


     string stdout; 
     char buffer[MAX_BUFFER]; 
     FILE *stream = popen(cmd.c_str(), "r"); 
     while (fgets(buffer, MAX_BUFFER, stream) != NULL) 
     stdout.append(buffer); 
     pclose(stream); 


     cout << endl << "output: " << endl << stdout << endl; 
} 
+0

hará que el trabajo con argumentos así? – topherg

+0

Bueno, el cin soltará los argumentos, pero si los relacionas correctamente con getline, popen puede manejar algo "ls -latr". – Ternary

4

desconfío popen/pclose, ya que he trabajado en muchos sistemas en los que se manejó SIGCHLDligeramente diferente. Y desconfío del sh -shell parsing utilizado por popen, ya que raramente lo uso.

El corto de 22 años de edad, libro de O'Reilly Using C on the UNIX System, by Dave Curry sigue siendo una muy buena referenciapara este tipo de cosas.

De todos modos, aquí hay algunos códigos. Es un poco largo, ya que analiza la cadena de muestra "/bin/ls /etc" en la matriz {"/bin/ls", "/etc", 0}. Pero me parece que el uso del formato de cadena más fácil y es más corto el 98% del tiempo, aunque este ejemplo desmiente eso.

Este código genera una lista de /etc.. Deberá cambiar algunas cosas, como p. Ej. NUMBER() que es lo mismo que XtNumber(). Y deberá decidir si coincide con su manejo de SIGCHLD.

int main(void) { // list the files in /etc 
    char buf[100]; 
    FILE *fp; 
    int pid = spawnfp("/bin/ls /etc", &fp); 
    while (fgets(buf, sizeof buf, fp)) 
     printf("%s", buf); 
    fclose(fp);     // pclose() replacement 
    kill(pid, SIGKILL);   // pclose() replacement 
    return 0; 
} 

Las subrutinas aquí son:

static int spawnpipe(const char *argv[], int *fd) // popen() replacement 
{ 
    int pid; 
    int pipe_fds[2]; 

    if (pipe(pipe_fds) < 0) 
     FatalError("pipe"); 

    switch ((pid = fork())) 
    { 
     case -1: 
     FatalError("fork"); 
     case 0:      // child 
     close(1); 
     close(2); 
     dup(pipe_fds[0]); 
     dup(pipe_fds[1]); 
     close(pipe_fds[0]); 
     close(pipe_fds[1]); 

     execv(argv[0], (char * const *)argv); 
     perror("execv"); 
     _exit(EXIT_FAILURE); // sic, not exit() 
     default: 
     *fd = pipe_fds[0]; 
     close(pipe_fds[1]); 
     return pid; 
    } 
} 

Esto convierte una cadena ASCII a una lista argv, que es probablemente inútil para usted:

Bool convertStringToArgvList(char *p, const char **argv, int maxNumArgs) 
{ 
    // Break up a string into tokens, on spaces, except that quoted bits, 
    // with single-quotes, are kept together, without the quotes. Such 
    // single-quotes cannot be escaped. A double-quote is just an ordinary char. 
    // This is a *very* basic parsing, but ok for pre-programmed strings. 
    int cnt = 0; 
    while (*p) 
    { 
     while (*p && *p <= ' ') // skip spaces 
     p++; 
     if (*p == '\'')   // single-quote block 
     { 
     if (cnt < maxNumArgs) 
      argv[cnt++] = ++p; // drop quote 
     while (*p && *p != '\'') 
      p++; 
     } 
     else if (*p)    // simple space-delineated token 
     { 
     if (cnt < maxNumArgs) 
      argv[cnt++] = p; 
     while (*p > ' ') 
      p++; 
     } 
     if (*p) 
     *p++ = 0;    // nul-terminate 
    } 
    if (cnt < maxNumArgs) 
     argv[cnt++] = 0; 
    return cnt <= maxNumArgs;  // check for too many tokens (unlikely) 
} 

Esto convierte la cadena de argumentos a los tokens y, más importante aún, el fd a un fp, ya que el OP solicitó stdout:

int spawnfp(const char *command, FILE **fpp) 
{ 
    const char *argv[100]; 
    int fd, pid; 
    if (!convertStringToArgvList(strdupa(command), argv, NUMBER(argv))) 
     FatalError("spawnfp"); 
    pid = spawnpipe(argv, &fd); 
    *fpp = fdopen(fd, "r"); 
    return pid; 
} 
Cuestiones relacionadas