2011-12-08 5 views

Odpowiedz

6

execvpzastępuje bieżący proces uruchomiony w pamięci. Nie ma "łapania" wyjścia.

Podejrzewam, że próbujesz uruchomić proces zewnętrzny z istniejącego procesu i przeanalizować jego wynik. W tym celu należy użyć wartości popen(), która pobiera fork(), a następnie exec(), zwracając FILE * do odczytu (co będzie oznaczać stdout procesu, który właśnie uruchomiłeś).

1

Zobacz dokumentację popen, myślę, że to dokładnie to, czego potrzebujesz.

1

Jak powiedzieli inni, popen jest tym, czego chcesz użyć. Coś takiego ...

#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

będzie to również działać z argumentami? – topherg

+0

Cóż, cin rzuci argumenty, ale jeśli je odpowiednio poprowadzisz w linii, popen poradzi sobie z czymś "ls-latr". – Ternary

4

ufam popen/pclose, jak ja pracowałem na zbyt wielu systemach, gdzie SIGCHLD zostało obsłużonych nieznacznie inaczej. I nie ufam analizie składni parsowania sh używanej przez popen, ponieważ rzadko jej używam.

Krótka 22-letnia O'Reilly książka Using C on the UNIX System, by Dave Curry wciąż bardzo dobre odniesienie do tego rodzaju rzeczy.

W każdym razie, oto kod. Trochę to trwa, ponieważ analizuje przykładowy ciąg "/bin/ls /etc" w tablicy {"/bin/ls", "/etc", 0}. Ale uważam, że używanie formatu ciągu łatwiejsze jest 98% czasu, chociaż ten przykład to przeczy.

Ten kod generuje listę /etc. Będziesz musiał zmienić niektóre rzeczy, na przykład NUMBER(), który jest taki sam jak XtNumber(). I musisz zdecydować, czy pasuje do twojej obsługi z 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; 
} 

Tutejsze podprogramy są:

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; 
    } 
} 

ten konwertuje ciąg znaków ASCII do listy argv, który jest prawdopodobnie bezużyteczny dla Ciebie:

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) 
} 

ten przekształca ciąg argumentów na żetony i, co ważniejsze, fd do fp, ponieważ OP wymagał 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; 
}