外部プロセスを作るには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のファイルディスクリプタ
-