- 论坛徽章:
- 0
|
请教各位一个关于管道的问题,如何获取系统命令的结果??谢谢
很早以前写的了
是一个通用的函数
取名lazy提醒自己少用这样的方式
果然一次也没用过
hoho
- #include "../my.h"
- /*功能说明:这个函数用来调用外部程序(任何程序都可以,包括各种脚本),并且将外部程序的标准输出结果保存到一块内存中(内存可写),函数返回
- 这块内存的指针,调用者可以直接printf这个指针,!!!!!!!!!!!!!!!!最后一定要记得free!!!!!!!!!!!!
- 两种使用方法:lazy("ls -al /root"),lazy("ls",{"ls", "-al", "/root", (char *)0})
- 思路简述:用了两个进程一个管道,子进程调用system或者exec执行shell,并且把输出重定向到管道,父进程则从管道将数据读出,根据读出数据的数量自动扩展缓冲区大小
- 两个地方值得回味:1,关闭文件描述符,一些不用的文件描述符要关闭,很多时候都出现了管道阻塞,这个时候去proc里看看到底是哪些多余的描述符没有关闭,关掉它们那就好了
- 2,如何打开被关闭的标准输出,有两种办法(a,用dup复制,以后再用dup2拷贝回来,本程序就是用这个办法.b,调用ttyname(1)查看当前打开的是哪个终端,然后再用open打开就行了)
- 命名来历:用这个函数之前问问自己,我写的还是C语言程序吗?
- */
- char *lazy(char *pCmd, char **env) {
- char *pResult, *p;
- int fd[2], fd_stdout;
- int count=0;
- int a1 = 0, a2 = 0; //a1缓冲区总大小,a2缓冲区使用了多少
- int maxlen = 4096; //为什么使用4096?因为这刚好是管道的大小,可以参考~/code/ipc/pipe/question.c里的Q4
- fd_stdout = dup(1); //备份stdout,关闭之后想要再使用标准输出要靠这个备份的
- pipe(fd);
- close(1);
- dup2(fd[1],1);
- if (fork() == 0) {
- close(fd[1]);
- close(fd[0]);
- close(fd_stdout);
- if (env == NULL) //exec和system都可以,不同的调用方法用不同的实现吧,呵呵
- system(pCmd); //调用方法:lazy("ls -al /root")
- else
- execvp(pCmd, env); //调用方法:lazy("ls",{"ls", "-al", "/root", (char *)0})
- exit(1);
- }
- close(fd[1]);
- close(1);
- fflush(stdout);
- dup2(fd_stdout, 1); //打开stdout
- pResult = malloc(maxlen + 1);
- a1 += maxlen + 1;
- p = pResult;
- while ((count = read(fd[0], pResult, maxlen)) >; 0) { //如果在read过程中超过了缓冲区边缘会返回-1,调试了很久才发现这个问题
- a2 += count;
- if (a1 - a2 <= maxlen) {
- p = realloc(p, a1 + maxlen); //为什么要用个临时变量p来帮忙呢?:)这是一个小发现呵呵,看<Linux函数库参考手册>;P33的笔记
- pResult = p + a2;
- a1 += maxlen;
- continue;
- }
- pResult += count;
- }
- *pResult = 0; //打上字符串结束符
- close(fd[0]);
- wait(&count);
- return p;
- }
- int main(void) {
- char *result;
- char *cmd = "ls";
- char *cmd2 = "ls /dev";
- char *env[] = {"ls", "-al", "/dev", (char *)0};
- //result = lazy(cmd, env);
- result = lazy(cmd2, NULL);
- printf("%s", result);
- free(result);
- return 0;
- }
复制代码 |
|