6

execvpシステムがターミナルで出力(Linuxの場合はc)を印刷する代わりに、出力(stdoutだと思います)をキャッチする方法を知っている人はいますか?

4

5 に答える 5

6

execvp メモリ内で現在実行中のプロセスを置き換えます。出力を「キャッチ」することはありません。

既存のプロセスから外部プロセスを実行し、その出力を解析しようとしていると思われます。そのためpopen()には、 which を実行してから を使用し、 afork()を読み取りexec()に返す必要があります (これは、実行したプロセスの になります)。FILE *stdout

于 2011-12-08T02:38:56.043 に答える
4

popen/pclose私はあまりにも多くのシステムに取り組んできましたSIGCHLDが、処理がわずかに異なっていたため、信頼できません。shまた、 で使用される -shell 構文解析はpopen、めったに使用しないため、信用できません。

Dave Curry による22 年前の O'Reilly の短い本Using C on the UNIX Systemは、この種のものについては今でも非常に良いリファレンスです。

とにかく、ここにいくつかのコードがあります。"/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)
}

OPが要求しfdたため、これは引数文字列をトークンに変換し、さらに重要なことに、をに変換します。fpstdout

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;
}
于 2011-12-08T05:21:19.973 に答える
1

のドキュメントを参照してくださいpopen。まさにあなたが必要としているものだと思います。

于 2011-12-08T02:31:13.537 に答える
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;
}
于 2011-12-08T02:38:32.903 に答える