当你不得不在 C++ 程序中调用脚本的时候,将就着用 system()?No,我有更好的方法,不仅可以捕获脚本输出,还能实现调用超时。
C++ 中几种创建进程和调用脚本方式:
system() 无能为力的地方:
使用 fork + execlp + pipe 虽然复杂一些,但是可以通过进程间的管道来重定向脚本的标准输出,从而拿到脚本的执行日志和返回值,同时可以设置超时时间,比 system() 简单的调用要优雅不少。
小技巧
实例代码
int pipefd[2];
ret = pipe(pipefd);
if((pid = fork()) == 0) {
// child process
close(pipefd[0]);
dup2(pipefd[1], 1);
switch(param_count) {
case 0:
ret = execlp(cmd, cmd, NULL);
break;
case 2:
ret = execlp(cmd, cmd, param[0], param[1], NULL);
break;
default:
break;
}
if (ret) {
printf("execlp run error %s\n", cmd);
}
} else if(pid > 0) {
// parent process
int read_size;
char buffer[32]="";
char *ptr = res_buf;
int overflow = 0;
close(pipefd[1]);
int res_len = 0;
while ((read_size = read(pipefd[0], buffer, sizeof(buffer)-1)) != 0) {
buffer[read_size] = '\0';
if (read_size + res_len < res_buf_len) {
strcpy(ptr + res_len, buffer);
if (buffer[read_size - 1] == 0) {
break;
}
} else {
overflow = 1;
break;
}
res_len += read_size;
}
if (overflow) {
while ((read_size = read(pipefd[0], buffer, sizeof(buffer)-1)) != 0) {}
log2(g_log, "%s output overflow\n", cmd);
}
waitpid(pid, &status, 0);
//调用超时的实现逻辑: while(timeout){waitpid(pid, &status, WNOHANG);sleep(1);}
close(pipefd[0]);
} else {
close(pipefd[0]);
close(pipefd[1]);
snprintf(res_buf, res_buf_len, "fork error");
log2(g_log, "%s fork error\n", cmd);
return -1;
}