2011-12-08 8 views
6

有誰知道如何捕捉到輸出獲取標準輸出(我認爲它的標準輸出)從execvp而不是系統的終端打印出來(在Linux下C)?從執行的應用

回答

6

execvp替換內存當前正在運行的進程。沒有「捕捉」輸出。

我懷疑你正試圖從現有的進程中運行外部進程,並分析其輸出。對於那些需要使用popen()它做了fork()那麼exec(),返回FILE *閱讀(這將是您剛剛運行的進程的stdout)。

1

popen的文檔,我認爲這正是你所需要的。

1

正如其他人所說,popen是你要使用的東西。事情是這樣的......

#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

那麼,它們是否也可以使用參數? – topherg

+0

那麼cin會放棄參數,但是如果你正確地使用w/getline,你可以處理一些「ls -latr」。 – Ternary

4

我不信任popen/pclose,正如我在哪裏SIGCHLD被處理略有不同太多的系統工作。我不信任由popen使用的sh-shell解析,因爲我很少使用它。

短22歲的奧賴利書Using C on the UNIX System, by Dave Curry仍然是這種東西一非常很好的參考。

無論如何,這裏是一些代碼。它有點冗長,因爲它將樣本字符串"/bin/ls /etc"解析爲數組{"/bin/ls", "/etc", 0}。但我發現使用字符串格式更容易縮短98%的時間,雖然這個例子勉強。

此代碼生成/etc.的列表您需要更改一些內容,例如, NUMBER(),這與XtNumber()相同。你需要決定它是否符合你的處理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; 
} 

在這裏子程序是:

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

這一個ASCII字符串轉換爲argv列表中,這可能是沒用的,你:

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

該轉換參數字符串令牌並且更重要的是,fdfp,因爲OP請求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; 
}