有这样一种需求,希望让程序调用fdisk、mysql、sqlplus这种可以交互的命令,执行一些操作后分析输出结果,然后再根据这些结果决定如何执行下面的命令。这样就可以代替人工的判断和键盘输入。
这种需求可以用管道来接管子进程的标准输入输出,甚至标准错误来完成。
具体方法是
1 用pipe(int)创建两个管道,分别用于连接程序和要调用的命令的标准输入和标准输出。暂时叫他们“输入管道”和“输出管道”。
2 fork()一下,在父进程和子进程分别关闭两个管道的一端。
输入管道对主进程相当于键盘,因此关闭管道的读端,而子进程关闭写端。
输出管道对主进程相当于显示器,因此关闭管道的写端,而子进程关闭读端。
3 在子进程用dup2()。
将子进程的标准输入复制为输入管道的读端。
将子进程的标准输出复制为输出管道的写端。
4 在子进程调用execl来执行需要的命令。
5 在父进程写入输入管道的写端,然后读取输出管道的读端。
-
#include <stdio.h>
-
#include <unistd.h>
-
#include <errno.h>
-
#include <stdlib.h>
-
#include <fcntl.h>
-
#include <string.h>
-
-
int lsexec2(int* in, int* out, char* path, char* cmd, char* arg)
-
{
-
int fd_i[2];
-
int fd_o[2];
-
char buf[BUFSIZ];
-
int len = 0;
-
-
// 创建两个管道,fd_i用于接管子进程的标准输入,fd_o用于标准输出
-
pipe(fd_i);
-
pipe(fd_o);
-
-
pid_t p = fork();
-
if(p < 0) return -1;
-
if(p > 0)
-
{ //parent
-
close(fd_i[0]); // 关闭输入管道的读端
-
*in = fd_i[1]; // 将写端暴露给调用者,这样调用者可以给子进程发送命令
-
close(fd_o[1]); // 关闭输出管道的写端
-
*out = fd_o[0]; // 将读端暴露给调用者,这样调用者可以读取子进程的输出
-
return 0;
-
}
-
else
-
{ //child
-
close(fd_i[1]); // 关闭输入管道的写端
-
dup2(fd_i[0], STDIN_FILENO); // 将标准输入复制到输入管道的读端,这样就可以把父进程的输入转接到标准输入
-
close(fd_o[0]); // 关闭输出管道的读端
-
dup2(fd_o[1], STDOUT_FILENO); // 将标准输出复制到输出管道的写端,这样父进程就可以通过读端读取标准输出的内容
-
return execl(path, cmd, arg, (int*)0); // 执行需要的命令
-
}
-
}
-
-
int main(void)
-
{
-
int in, out;
-
char cmd[BUFSIZ];
-
memset(cmd, '\0', BUFSIZ);
-
-
if(lsexec2(&in, &out, "/sbin/fdisk", "fdisk", "/dev/sda") == -1)
-
{
-
printf("%s\n", strerror(errno));
-
exit(1);
-
}
-
strcpy(cmd, "p\nm\n");
-
write(in, cmd, strlen(cmd)); // 向in写入指令,模拟人工键盘输入
-
usleep(10000); // 由于只是demo,简单等待10毫米,让子程序输出完整。正常应该是新开一个进程持续等待子进程输出。
-
char buf[BUFSIZ];
-
int len = read(out, buf, BUFSIZ); // 读取out的内容,让程序看到命令的输出内容
-
printf("%s", buf);
-
return 0;
- }
执行效果
[root@server2 c]# ./a
WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u').
Command (m for help):
Disk /dev/sda: 34.4 GB, 34359738368 bytes
255 heads, 63 sectors/track, 4177 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000ac07a
Device Boot Start End Blocks Id System
/dev/sda1 1 1045 8388608 82 Linux swap / Solaris
/dev/sda2 * 1045 4178 25164800 83 Linux
Command (m for help): Command action
a toggle a bootable flag
b edit bsd disklabel
c toggle the dos compatibility flag
d delete a partition
l list known partition types
m print this menu
n add a new partition
o create a new empty DOS partition table
p print the partition table
q quit without saving changes
s create a new empty Sun disklabel
t change a partition's system id
u change display/entry units
v verify the partition table
w write table to disk and exit
x extra functionality (experts only)
Command (m for help): [root@server2 c]#
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26239116/viewspace-2120901/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/26239116/viewspace-2120901/
692

被折叠的 条评论
为什么被折叠?



