LoginSignup
1
2

More than 5 years have passed since last update.

fork execしたプロセスの標準出力をリダイレクトする

Last updated at Posted at 2017-05-02

外部プロセスを作るにはsystem関数を使ったり、fork&execしたりするが、ここでは後者の方法で外部プロセスを起動したときに標準出力をリダイレクトする方法を書く。

ほぼこのページの和訳
http://stackoverflow.com/questions/2605130/redirecting-exec-output-to-a-buffer-or-file

手順の概要

UNIX系のシステムでは、file descriptorの1,2が標準出力、標準エラー出力に対応する。

open関数を使ってファイルを開き、そのファイルディスクリプタをdup2関数で複製する。
http://man7.org/linux/man-pages/man2/open.2.html
https://linuxjm.osdn.jp/html/LDP_man-pages/man2/dup.2.html

サンプル

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <vector>
#include <string>

int my_system(std::vector<std::string> args) {
  pid_t pid;

  if ((pid = fork()) == 0) {
    char** arg = NULL;
    arg = new char*[args.size() + 1 ];
    for( size_t i=0; i<args.size(); i++ ) {
      arg[i] = (char*) args[i].c_str();
    }
    arg[ args.size() ] = NULL;

    int fd_out = open("_stdout", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    int fd_err = open("_stderr", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    // read only, create a file if not exist, read permission, write permission
    dup2( fd_out, 1 );
    dup2( fd_err, 2 );
    close( fd_out );
    close( fd_err );

    int rc = execvp( arg[0], (char*const*) arg );
    std::cerr << "failed to execute the command. rc : " << rc << std::endl;
    exit(-1);
  }
  else if (pid > 0) {
    std::cout << "pid: " << pid << std::endl;
    int status = 0;
    int ret = waitpid(pid, &status, 0);

    if( WIFEXITED(status) ) {
      std::cerr << "exited with rc : " << WEXITSTATUS(status) << std::endl;
      return WEXITSTATUS(status);
    }
    else if( WIFSIGNALED(status) ) {
      std::cerr << "signaled by signal" << WTERMSIG(status) << std::endl;
      return -1;
    }
    else {
      std::cerr << "other" << std::endl;
      return -1;
    }
  }
  else {
    std::cerr << "failed to fork" << std::endl;
    return -1;
  }
}

int main(int argc, char *argv[])
{
  std::vector<std::string> args;
  args.push_back("/usr/bin/ruby");
  args.push_back("-e");
  args.push_back("puts 'hello'; $stderr.puts 'world'");

  int rc = my_system( args );

  return 0;
}
  • open関数の第二引数
    • O_RDWRは読み書き可能なモードでファイルを開く
    • O_CREATはファイルが存在しなかったら作成する。
    • S_IRUSR, S_IWUSR はファイルのpermissionを0600にする。
  • dup2でファイルのディスクリプタを1,2に複製した後は、close関数を呼んで閉じてしまって良い。(なんで閉じてもよいのかはわからない)
    • 1,2がstdout, stderrのファイルディスクリプタ
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2