的Linux 3.0:与管道标准输入执行子进程/标准输出
在Linux 3.0/C++:的Linux 3.0:与管道标准输入执行子进程/标准输出
我想,做了以下的功能:
string f(string s)
{
string r = system("foo < s");
return r;
}
显然,上述方法无效,但你明白了。我有一个字符串s,我想作为应用程序“foo”的子进程执行的标准输入来传递,然后我想将其标准输出记录到字符串r,然后返回它。
我应该使用什么linux系统调用或posix函数的组合?
由eerpini提供的代码不能按照书面形式工作。请注意,例如,之后使用在父项中关闭的管道末端。看看
close(wpipefd[1]);
和随后写入该封闭描述符。这只是换位,但它显示此代码从未被使用过。以下是我测试过的一个版本。不幸的是,我改变了代码风格,所以这不被接受为eerpini代码的编辑。
唯一的结构性变化是我只重定向子项中的I/O(注意dup2调用只在子路径中)。这非常重要,否则父项I/O会混乱。感谢eerpini提供的初始答案,我在开发这个答案时使用了这个答案。
#define PIPE_READ 0
#define PIPE_WRITE 1
int createChild(const char* szCommand, char* const aArguments[], char* const aEnvironment[], const char* szMessage) {
int aStdinPipe[2];
int aStdoutPipe[2];
int nChild;
char nChar;
int nResult;
if (pipe(aStdinPipe) < 0) {
perror("allocating pipe for child input redirect");
return -1;
}
if (pipe(aStdoutPipe) < 0) {
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
perror("allocating pipe for child output redirect");
return -1;
}
nChild = fork();
if (0 == nChild) {
// child continues here
// redirect stdin
if (dup2(aStdinPipe[PIPE_READ], STDIN_FILENO) == -1) {
exit(errno);
}
// redirect stdout
if (dup2(aStdoutPipe[PIPE_WRITE], STDOUT_FILENO) == -1) {
exit(errno);
}
// redirect stderr
if (dup2(aStdoutPipe[PIPE_WRITE], STDERR_FILENO) == -1) {
exit(errno);
}
// all these are for use by parent only
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);
// run child process image
// replace this with any exec* function find easier to use ("man exec")
nResult = execve(szCommand, aArguments, aEnvironment);
// if we get here at all, an error occurred, but we are in the child
// process, so just exit
exit(nResult);
} else if (nChild > 0) {
// parent continues here
// close unused file descriptors, these are for child only
close(aStdinPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);
// Include error check here
if (NULL != szMessage) {
write(aStdinPipe[PIPE_WRITE], szMessage, strlen(szMessage));
}
// Just a char by char read here, you can change it accordingly
while (read(aStdoutPipe[PIPE_READ], &nChar, 1) == 1) {
write(STDOUT_FILENO, &nChar, 1);
}
// done with these in this example program, you would normally keep these
// open of course as long as you want to talk to the child
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
} else {
// failed to create child
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);
}
return nChild;
}
谢谢,最后是一段完整的工作代码。 – minastaros 2017-05-12 12:53:19
由于您希望双向访问进程,因此您必须使用管道明确执行popen在后台执行的操作。我不知道是否有任何这将在C更改++,但这里是一个纯C例如:
void piped(char *str){
int wpipefd[2];
int rpipefd[2];
int defout, defin;
defout = dup(stdout);
defin = dup (stdin);
if(pipe(wpipefd) < 0){
perror("Pipe");
exit(EXIT_FAILURE);
}
if(pipe(rpipefd) < 0){
perror("Pipe");
exit(EXIT_FAILURE);
}
if(dup2(wpipefd[0], 0) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
if(dup2(rpipefd[1], 1) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
if(fork() == 0){
close(defout);
close(defin);
close(wpipefd[0]);
close(wpipefd[1]);
close(rpipefd[0]);
close(rpipefd[1]);
//Call exec here. Use the exec* family of functions according to your need
}
else{
if(dup2(defin, 0) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
if(dup2(defout, 1) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
close(defout);
close(defin);
close(wpipefd[1]);
close(rpipefd[0]);
//Include error check here
write(wpipefd[1], str, strlen(str));
//Just a char by char read here, you can change it accordingly
while(read(rpipefd[0], &ch, 1) != -1){
write(stdout, &ch, 1);
}
}
}
有效地这样做:
- 创建管道和重定向标准输出和标准输入到端(注意在linux中,pipe()创建单向管道,所以你需要使用两个管道来达到你的目的)。
- Exec现在将启动一个新的进程,其中包含stdin和stdout的管道末端。
- 关闭未使用的描述符,将该字符串写入管道,然后开始读取任何进程可能转储到另一个管道的内容。
DUP()用于创建在文件描述符表中的重复条目。而dup2()更改描述符指向的内容。
注意:正如Ammo @在他的解决方案中所提到的,我上面提供的或多或少是一个模板,如果您只是试图执行代码,它就不会运行,因为明显存在exec *(函数族)丢失了,所以孩子将在fork()后立即终止。
为什么在用dup2重定向时保留对dup的标准输入/标准输出的引用? dup2隐式关闭你的第二个参数。 – 2015-09-25 21:22:15
你是对的,那是不必要的。上面的答案是正确的做法,请参阅。 – eerpini 2015-10-03 00:40:44
Ammo的代码有一些错误处理错误。子进程在dup失败后返回,而不是退出。
if (dup2(aStdinPipe[PIPE_READ], STDIN_FILENO) == -1 ||
dup2(aStdoutPipe[PIPE_WRITE], STDOUT_FILENO) == -1 ||
dup2(aStdoutPipe[PIPE_WRITE], STDERR_FILENO) == -1
)
{
exit(errno);
}
// all these are for use by parent only
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);
的[?我怎么能运行在C外部程序,并解析其输出(
你是对的。子进程不应该从堆栈框架返回,也不应该尝试打印错误。可能没有人注意到,因为这从来没有发生过。 – 2017-08-30 23:08:59
更新了上面的代码 – 2017-08-30 23:47:21
可能重复http://stackoverflow.com/questions/43116/how-can:也许孩子的DUP可以替换-i-run-an-external-program-from -c-and-parse-its-output) – 2012-02-23 01:54:46
什么是“Linux 3.0”? – Joe 2012-02-23 02:06:33
@Joachim Pileborg:不,它不是重复的,我需要stdin和stdout。 popen是单向的(stdin或stdout,不是两者)。 – 2012-02-23 02:10:18