2008-09-16 13 views
7

Cプログラム内で別のプログラムを実行するにはどうすればよいですか?私は起動したプログラムのSTDINにデータを書き込むことができなければなりません。STDOUTCプログラム内からプログラムを実行

これは標準のC関数であるかわかりません。私はLinux上で動作するはずのソリューションが必要です。

+0

これは、この質問の重複です:http://stackoverflow.com/questions/17140/how-do-you-spawn-another-process-in-c –

答えて

17

popenを使用します。これは、プログラムのstdinとstdoutにアクセスできる単方向パイプを提供します。

popenのは、Linuxはそれについての詳細を読むための端末で1つの:-)

タイプ

man popen 

となっている現代のUNIXおよびUNIX系OS、上の標準です。 popenは、単方向または双方向のパイプを生産するかどうか

EDIT

は実装に依存します。 LinuxおよびOpenBSDでは、popenは、読み取り専用または書き込み専用の一方向性パイプを生成します。 OS X上では、FreeBSDNetBSD が双方向パイプを生成します。

+1

。なお、 stdinまたはstdoutであり、一度に両方ではありません。 – wnoise

+0

最近の実装では、stdinとstdoutです。伝統的には一方向ですが、パイプは双方向にすることができます。 – freespace

+0

Ubuntu 9.04の "man popen"は、 "パイプは単方向で定義されているので、型引数は両方ともではなく、読み書きしか指定できない"という。 – nobar

0

私はあなたがこのために

freopen

を使用することができると思います。

7
  1. pipe(...)との2本のパイプ、stdinに1つ、stdoutのための1つを作成します。
  2. fork(...)プロセス。
  3. 子プロセス(fork(...)が0を返す)でstdin/stdoutにパイプdup (...)を接続します。
  4. exec[v][e]子プロセスの起動するプログラムファイル。親プロセス子のPIDを返します(forkは、1))で
  5. は 子を終了する(waitpid(...))まで、子供のstdoutselect(...)またはpoll(...)read(...))バッファに読み込んでからループを実行します。
  6. 最終的には、若干の入力がある場合は、stdinに入力してください。
  7. 完了時close(...)パイプ。あなたは、システムコールを使用することができます
4

を読んで、私はネイサンFellmanに反対 - 被写体が関連しているものの、他の質問は、このの複製ではありません。

単純な単方向通信の場合、popen()はまともな解決策です。しかし、それは双方向通信には役に立たない。

IMO、imjorge(Jorge Ferreira)は、双方向通信のほとんどの答え(80%?)を示しましたが、いくつかの重要な詳細は省略しました。

  1. 親プロセスは、子プロセスにメッセージを送信するために使用されるパイプの読み取り側を閉じることが重要です。
  2. 子プロセスは、メッセージを子プロセスに送信するために使用されるパイプの書き込み終了を閉じることが重要です。
  3. 親プロセスがメッセージを親プロセスに送信するために使用されるパイプの書き込み終了を閉じることが重要です。
  4. 子プロセスが親プロセスにメッセージを送信するために使用されるパイプの読み込み終了を閉じることが重要です。

パイプの未使用の端を閉じないと、プログラムの1つが終了すると分かりません。たとえば、子が標準入力から読み込んでいる可能性がありますが、パイプの書き込み終了が子で閉じられていないと、パイプが開いていてシステムがそれを認識しているため、EOF(読み取りからゼロバイト)たとえそれが現在何かを読むのを待っているにもかかわらず、いつかパイプに書き込むことになるかもしれません。

書き込みプロセスでは、読み取りプロセスがないパイプに書き込むときに指定されたSIGPIPE信号を処理するかどうかを検討する必要があります。

パイプ容量(プラットフォームによって異なりますが、4KB程度かもしれません)に注意し、デッドロックを回避するようにプログラムを設計する必要があります。

8

私は、これを行う方法を示しながら、他の誰かのためにいくつかの例Cコードを書きました。ここではそれはあなたのためである:

#include <sys/types.h> 
#include <unistd.h> 
#include <stdio.h> 

void error(char *s); 
char *data = "Some input data\n"; 

main() 
{ 
    int in[2], out[2], n, pid; 
    char buf[255]; 

    /* In a pipe, xx[0] is for reading, xx[1] is for writing */ 
    if (pipe(in) < 0) error("pipe in"); 
    if (pipe(out) < 0) error("pipe out"); 

    if ((pid=fork()) == 0) { 
    /* This is the child process */ 

    /* Close stdin, stdout, stderr */ 
    close(0); 
    close(1); 
    close(2); 
    /* make our pipes, our new stdin,stdout and stderr */ 
    dup2(in[0],0); 
    dup2(out[1],1); 
    dup2(out[1],2); 

    /* Close the other ends of the pipes that the parent will use, because if 
    * we leave these open in the child, the child/parent will not get an EOF 
    * when the parent/child closes their end of the pipe. 
    */ 
    close(in[1]); 
    close(out[0]); 

    /* Over-write the child process with the hexdump binary */ 
    execl("/usr/bin/hexdump", "hexdump", "-C", (char *)NULL); 
    error("Could not exec hexdump"); 
    } 

    printf("Spawned 'hexdump -C' as a child process at pid %d\n", pid); 

    /* This is the parent process */ 
    /* Close the pipe ends that the child uses to read from/write to so 
    * the when we close the others, an EOF will be transmitted properly. 
    */ 
    close(in[0]); 
    close(out[1]); 

    printf("<- %s", data); 
    /* Write some data to the childs input */ 
    write(in[1], data, strlen(data)); 

    /* Because of the small amount of data, the child may block unless we 
    * close it's input stream. This sends an EOF to the child on it's 
    * stdin. 
    */ 
    close(in[1]); 

    /* Read back any output */ 
    n = read(out[0], buf, 250); 
    buf[n] = 0; 
    printf("-> %s",buf); 
    exit(0); 
} 

void error(char *s) 
{ 
    perror(s); 
    exit(1); 
} 
関連する問題