web-dev-qa-db-ja.com

exec出力をバッファーまたはファイルにリダイレクトする

fork()exec()、およびwait()のCプログラムを作成しています。実行したプログラムの出力をファイルまたはバッファーに書き込みたいのですが。

たとえば、lsを実行する場合、file1 file2 etcバッファ/ファイルへ。標準出力を読み取る方法はないと思うので、パイプを使用する必要があるということですか?ここに私が見つけることができなかった一般的な手順はありますか?

38
devin

出力を別のファイルに送信する場合(重要な詳細に焦点を合わせるためにエラーチェックを省略しています):

if (fork() == 0)
{
    // child
    int fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    dup2(fd, 1);   // make stdout go to file
    dup2(fd, 2);   // make stderr go to file - you may choose to not do this
                   // or perhaps send stderr to another file

    close(fd);     // fd no longer needed - the dup'ed handles are sufficient

    exec(...);
}

出力をパイプに送信して、出力をバッファーに読み込むことができます:

int pipefd[2];
pipe(pipefd);

if (fork() == 0)
{
    close(pipefd[0]);    // close reading end in the child

    dup2(pipefd[1], 1);  // send stdout to the pipe
    dup2(pipefd[1], 2);  // send stderr to the pipe

    close(pipefd[1]);    // this descriptor is no longer needed

    exec(...);
}
else
{
    // parent

    char buffer[1024];

    close(pipefd[1]);  // close the write end of the pipe in the parent

    while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
    {
    }
}
80

あなたが何をしたいのかを正確に決定する必要があります-そしてできればそれをもう少し明確に説明してください.

オプション1:ファイル

実行したコマンドの出力先のファイルがわかっている場合:

  1. 親と子が名前に同意することを確認します(親はフォークする前に名前を決定します)。
  2. 親フォーク-2つのプロセスがあります。
  3. 子は、ファイル記述子1(標準出力)がファイルに送られるように物事を再編成します。
  4. 通常、標準エラーはそのままにしておくことができます。/dev/nullから標準入力をリダイレクトできます。
  5. その後、子は関連するコマンドを実行します。上記のコマンドが実行され、標準出力がファイルに送信されます(これは基本的なシェルI/Oリダイレクトです)。
  6. その後、実行されたプロセスは終了します。
  7. 一方、親プロセスは次の2つの主な戦略のいずれかを採用できます。
    • 読み取り用にファイルを開き、EOFに達するまで読み取りを続けます。次に、子が死亡したかどうか(読み取りデータがこれ以上ないこと)を再確認するか、子からの追加入力を待機する必要があります。
    • 子が死ぬまで待ってから、読み取り用にファイルを開きます。
    • 最初の利点は、子が実行されている間に親がその作業の一部を実行できることです。 2番目の利点は、I/Oシステムをいじる必要がないことです(過去のEOFを繰り返し読む)。

オプション2:パイプ

親に子からの出力を読み取らせたい場合、子がその出力を親にパイプで戻すように手配します。

  1. これを簡単に行うにはpopen()を使用します。プロセスを実行し、親プロセスに出力を送信します。パイプのバッファサイズは小さい(多くの場合4〜5 KB)ため、子が出力を生成している間は親がアクティブである必要があります。親が読み取ります。親が子の死を待っている場合、デッドロックが発生します。
  2. Pipe()などを使用して、これを困難な方法で行います。親はpipe()を呼び出し、次にフォークします。子は配管を整理して、パイプの書き込み側がその標準出力になるようにし、パイプに関連する他のすべてのファイル記述子が閉じられるようにします。これはdup2()システムコールを使用する可能性があります。次に、必要なプロセスを実行し、標準出力をパイプに送信します。
  3. その間、親もパイプの不要な端を閉じてから、読み取りを開始します。パイプでEOFを取得すると、子が終了してパイプを閉じたことを認識し、パイプの終わりも閉じることができます。
14

Linux/cygwin環境でこれを使用するように見えるので、 popen を使用します。ファイルを開くようなもので、実行プログラムstdoutを取得するだけなので、通常のfscanffreadなどを使用できます。

2
Blindy

フォークした後、 dup2(2) を使用して、ファイルのFDをstdoutのFDに複製し、実行します。