(好久没更新了,呼…一大波死线刚刚结束…)
我几乎一直在用Bash,可是却少有接触到Unix系的系统编程,对系统调用还是知之甚少。这两天实验室里讨论了一个比较基础的问题: 在自己写的程序中,怎么样得到另一个可执行文件的输出?
比如我们有/bin/pwd这个可执行文件,我们可以在自己的程序中用
system("/bin/pwd");
或者是
execl("/bin/pwd",".",NULL);
调用它。
如果想要得到它的输出,应该怎么做比较好?
这个其实是作业题的范畴,涉及到了几个Unix的系统调用:
#include
pid_t
fork(void);
#include
int
pipe(int fildes[2]);
#include
int
dup(int fildes);
int
dup2(int fildes, int fildes2);
手册里有各个函数的详细解释。
在这个例子里,pipe用来生成一对文件描述子 (file descriptor,我觉得描述子这个翻译不是很好…),往第二个描述子里写内容,从第一个里面读内容。fork用来得到一个子进程,这里,我们会让子进程来执行pwd,并且把输出写到pipe的一端,然后父进程可以从另一端读入。
但是pwd默认输出到屏幕,也就是标准输出,我们需要使用dup2,把标准输出指向pipe的一端,这样就可以完成任务了。
所以,最终的代码是这样的
#include
#include
#include
#include
int main(int argc, char **argv)
{
int fd[2];
int pid;
pipe(fd);
int rpipe = fd[0];
int wpipe = fd[1];
pid = fork();
if (pid == 0)
{
/* 子进程关掉读的那端,只用写的一端 */
close(rpipe);
/* 把标准输入指向pipe的写的一端 */
dup2(wpipe, STDOUT_FILENO);
/* 执行pwd */
execl("/bin/pwd",".",NULL);
/* 嗯 */
exit(0);
}
else
{
/* 父进程关掉写的那端,只用读的一端 */
close(wpipe);
printf("begin parent process\n");
char readbuffer[1024];
/* 从读的这端读出pwd的输出 */
int nbytes = read(rpipe, readbuffer, sizeof(readbuffer));
printf("Received string: %s | %d\n", readbuffer, nbytes);
printf("end parent process\n");
wait(&pid);
}
return 0;
}
所以最后的输出就是像这样的
begin parent process Received string: /Users/XXX/XXXX | 16 end parent process
话说fork除了考试之外,似乎就没有用过了,代码还是写得太少了…
(Image from Github)
在Linux,如Ubuntu,需要增加两行:
#include
不然编译器找不到wait()的头文件
在printf行之前增加:
readbuffer[nbytes-1]=’x0′;
因为pwd的输出不是以0结尾的字符串,需要手工增加结尾的0字节。