管道管道管道

Unix的管道真的是很方便,我们经常这样用:

$ls -l|wc -l


用于统计一个目录下的文件数。这里如果详细说起来,涉及了进程组,会话的概念。当然最显眼的就是符号 | ,这是就是管道,下面我们说说上面的这句shell如何用c语言来写。为了更能说明问题,我们把结果写入一个文件中。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

void error_quit(char *msg)
{
fprintf(stderr,"%s\n",msg);
exit(1);
}

int main(int argc, char *argv[])
{
int fd[2]; //存放管道读写的描述符
int new_fd;

if(pipe(fd)==-1) //使用pipe创建管道,错误返回-1
error_quit("pipe error");
//fork,dup和dup2都在 unistd.h 中申明
switch(fork()){ // 偶然看到的写法,觉得新鲜。fork返回pid_t类型
case -1: error_quit("fork error");
case 0: //子进程返回0
/*
close(1); //关闭标准输出,为了下一句能把子进程的管道写描述符复制到标准输出

dup(fd[1]); //把子进程管道写描述符复制到一个新的描述符中,由于上面关闭了标准输出,系统会选取最小的描述符作为新描述符 */
dup2(fd[1],1);//这是另外一种写法。上面注释部分由于不是原子操作,所以可以用dup2函数,实现上面注释块的功能。
close(fd[0]); //关闭掉不用的描述符
close(fd[1]);
execlp("ls","ls -l",0); //在子进程空间执行ls命令
error_quit("try to exec ls");
break;
default:
close(0);
dup(fd[0]); //可以用dup2代替
close(fd[0]);
close(fd[1]);

if((new_fd = open("result.txt",O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))<0)
//打开一个文件,使用系统调用open,在fcntl.h中申明
error_quit("open result.txt error");
close(1); //关闭标准输出
dup(new_fd); //标准输出变成文件result.txt
execlp("wc","wc","-l",0);
error_quit("try to wc");
break;
}
exit(0);

}


现在保存,编译文件 pipe_test.c

$gcc -c pipe_test.c
...
$gcc -g -o pt pipe_test.o
...
$./pt
$cat result.txt
$28

你也可以试试是不是和 ls -l|wc -l 一样呢?
注意,父子进程之间的通讯。如果我们的子进程没有准备好数据怎么办?
对于管道,如果写进程停止,那么读进程读到0,表示结束。
如果读进程先停止,那么写进程将会收到一个SIGPIPE的信号,并且wirte返回-1,把errno设置为 EPIPE。

这就是无名管道。当然还有更复杂的FIFO,有名管道。
这里主要是要注意 dup的使用,学习如何重定向。对了,这里还忘记说了,文件描述符,也就是上面的0,1,2,3这些,是进程表中的一个索引,他指向文件表,文件表说明了这个文件的各种属性。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值