57

外部アプリケーションを起動しようとしていますsystem()- たとえば、system("ls"). 発生した出力をキャプチャして、別の関数に送信してさらに処理したいと考えています。C/C++ でそれを行う最善の方法は何ですか?

4

10 に答える 10

41

popenマニュアルから:

#include <stdio.h>

FILE *popen(const char *command, const char *type);

int pclose(FILE *stream);
于 2008-09-24T07:37:59.843 に答える
33

popen() 関数を試してください。system() のようなコマンドを実行しますが、出力を新しいファイルに送信します。ストリームへのポインターが返されます。

  FILE *lsofFile_p = popen("lsof", "r");

  if (!lsofFile_p)
  {
    return -1;
  }

  char buffer[1024];
  char *line_p = fgets(buffer, sizeof(buffer), lsofFile_p);
  pclose(lsofFile_p);
于 2008-09-24T07:39:10.997 に答える
8

編集:別の関数ではなく、別のプログラムに出力を渡したいと質問を誤解しました。popen() は、ほぼ確実に必要なものです。

システムは、シェルへのフル アクセスを提供します。引き続き使用したい場合は、system("ls > tempfile.txt") によって出力を一時ファイルにリダイレクトできますが、安全な一時ファイルを選択するのは面倒です。または、別のプログラムを介してリダイレクトすることもできます: system("ls | otherprogram");

popen() コマンドを推奨する人もいます。これは、出力を自分で処理できる場合に必要なものです。

FILE *output = popen("ls", "r");

これにより、コマンドの出力から読み取ることができる FILE ポインターが得られます。

また、pipe() 呼び出しを使用して、新しいプロセスを作成する fork()、それらの標準入出力を変更する dup2()、新しいプログラムを実行する exec()、および wait() と組み合わせて接続を作成することもできます。メインプログラムでそれらを待ちます。これは、シェルと同じようにパイプラインを設定しているだけです。詳細と例については、pipe() の man ページを参照してください。

于 2008-09-24T07:36:59.910 に答える
3

関数popen()などは stderr などをリダイレクトしません。そのつもりで書きpopen3()ました。

これは、私の popen3() のボウドラー化されたバージョンです。

int popen3(int fd[3],const char **const cmd) {
        int i, e;
        int p[3][2];
        pid_t pid;
        // set all the FDs to invalid
        for(i=0; i<3; i++)
                p[i][0] = p[i][1] = -1;
        // create the pipes
        for(int i=0; i<3; i++)
                if(pipe(p[i]))
                        goto error;
        // and fork
        pid = fork();
        if(-1 == pid)
                goto error;
        // in the parent?
        if(pid) {
                // parent
                fd[STDIN_FILENO] = p[STDIN_FILENO][1];
                close(p[STDIN_FILENO][0]);
                fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
                close(p[STDOUT_FILENO][1]);
                fd[STDERR_FILENO] = p[STDERR_FILENO][0];
                close(p[STDERR_FILENO][1]);
                // success
                return 0;
        } else {
                // child
                dup2(p[STDIN_FILENO][0],STDIN_FILENO);
                close(p[STDIN_FILENO][1]);
                dup2(p[STDOUT_FILENO][1],STDOUT_FILENO);
                close(p[STDOUT_FILENO][0]);
                dup2(p[STDERR_FILENO][1],STDERR_FILENO);
                close(p[STDERR_FILENO][0]);
                // here we try and run it
                execv(*cmd,const_cast<char*const*>(cmd));
                // if we are there, then we failed to launch our program
                perror("Could not launch");
                fprintf(stderr," \"%s\"\n",*cmd);
                _exit(EXIT_FAILURE);
        }

        // preserve original error
        e = errno;
        for(i=0; i<3; i++) {
                close(p[i][0]);
                close(p[i][1]);
        }
        errno = e;
        return -1;
}
于 2011-03-07T20:05:38.750 に答える
1

このページでは、 capture_the_output_of_a_child_process_in_cで、popen を使用する場合と fork/exec/dup2/STDOUT_FILENO アプローチを使用する場合の制限について説明します。

popen でtsharkの出力をキャプチャする際に問題が発生しています。

そして、この制限が私の問題かもしれないと推測しています:

出力を非同期に処理するのには適していない生のファイル記述子ではなく、stdio ストリームを返します。

他のアプローチで解決策がある場合は、この回答に戻ります。

于 2014-10-03T10:42:18.863 に答える
1

Windows では、system() を使用する代わりに CreateProcess を使用し、出力をパイプにリダイレクトしてパイプに接続します。

これはPOSIXの方法でも可能だと思いますか?

于 2008-09-24T07:37:55.460 に答える
1

関数popen()pclose()は、あなたが探しているものかもしれません。

例については、 glibc のマニュアルを参照してください。

于 2008-09-24T07:41:35.700 に答える
0

通常、2 つの異なるプロセスがメモリ空間を共有することはないため、標準 C でそれが可能かどうかは完全にはわかりません。私が考えることができる最も簡単な方法は、2 番目のプログラムがその出力をテキスト ファイル (programname > textfile.txt) にリダイレクトし、そのテキスト ファイルを読み込んで処理することです。しかし、それは最善の方法ではないかもしれません。

于 2008-09-24T07:34:56.200 に答える