Linux操作系统pipe()-execlp()-dup2()分析

Linux操作系统pipe()-execlp()-dup2()分析

目标:使用Linux system call API实现sort | uniq | wc -l < data.txt。

涉及的知识点:

  1. 使用C调用shell命令
  2. 使用管道,在各命令间通信
  3. 标准输入输出重定向

execlp()执行shell command

头文件:<unistd.h>

函数原型:

       int execlp(const char *file, const char *arg, ... (char  *) NULL);

函数说明:

       execlp()会PATH环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件。arg为命令名,后跟参数列表,可以为空(NULL)。最后一个参数必须用空指针(NULL)作结束。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了。

使用示例:

       execlp(“/bin/ls”, “ls”, NULL);

pipe()管道

头文件:< unistd.h>

函数原型:

       int pipe(int pipefd[2]);

函数说明:

       pipe()会创建一个管道,它仅能实现单向通信,引用于进程间通信中。函数返回两个整型值分别指向管道输出输出文件描述符,其中pipefd[0]指向管道读端,而pipefd[1]指向管道的写端。写入管道的数据由kernel中开的缓冲区存储,直到另一端读取。也就是说这个缓冲区有大小,一般为4k bytes。

使用示例:

       int fd[2];

       if(pipe(fd) == -1){

              perror();

              return ;

       }

       使用fork()克隆子进程时,父进程创建出的管道的文件描述符被复制,所以子进程也有相同文件描述副本,两者指向同一个管道。两进程可通过此管道完成通信。本次实验目的为将sort命令输出通过管道传递数据,作为uniq的输入,同理,uniq的输出作为wc的输入。

       现在剩下最后一个问题,uniq,wc命令输入方式由两种,标准输入或文件。通过文件的方式,需要先读取命令的输出,写至文件中,最后让下一命令读该文件。此方式操作较为麻烦,还需要处理中间文件。另一种方式,使用重定向。这里需要使用dup2()的方法。

dup2()实现重定向

头文件:<unistd.h>

函数原型:

       int dup2(int oldfd, int newfd);

       int dup(int oldfd);

函数说明:

       先说dup(),此系统调用会创建一个oldfd文件描述符副本,并使用一个最小未使用的整数作为新的文件描述符。此后,oldfd和newfd可以互换使用,它们指向同一个打开的文件描述符,因此共享文件偏移和文件状态标志。但两个文件描述符不会共享文件描述符的标志位。函数返回值为newfd。

       那么使用dup怎么重定向呢?

       close(1);                              //关闭标准输出文件描述符

       int newfd = dup(oldfd);       //此时,newfd为1

       printf(“hello,world!\n”);       //此时,本应输出至stdout,被重定向至oldfd中。

       再说dup2(),该函数于dup类似。不同的是,dup2()不会使用最小未使用整数作为新的文件描述符,而是使用参数newfd的文件描述符作为newfd。如果此时的参数newfd已被打开暂用,则该函数会先关闭它,然后再使用。函数返回值是参数newfd的文件描述符。本例正是使用该函数。

使用示例:

       dup2(oldfd, STDOUT_FILENO);   //仅一句,已实现STDOUT_FILENO重定向至oldfd。

本例目标源码

#include <stdio.h>
#include <unistd.h>		//pipe, fork
#include <string.h>		//strlen
#include <sys/wait.h>		//wait
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>

int main(int argc[], char *argv[])
{
	int fd1[2], fd2[2];				//pipe
	pid_t fpid;
	
	if(pipe(fd1) == -1){
		perror("pipe fd1");
		return 1;
	}
	fpid = fork();
	if(fpid < 0){
		perror("fork");
		return 1;
	}
	if(fpid == 0){		// child process
		printf("sort process, id is %d\n", getpid());
		if(dup2(fd1[1], STDOUT_FILENO) == -1){
			perror("dup2");
			return 1;
		}	
		close(fd1[0]);		
		if(execlp("/usr/bin/sort", "sort", NULL) == -1){
			perror("sort");
			return 1;
		}
		//close(fd1[1]);
	}

	if(pipe(fd2) == -1){
		perror("pipe fd2");
		close(fd1[0]); close(fd1[1]);
		return 1;
	}
	fpid = fork();
	if(fpid < 0){
		perror("fork");
		close(fd1[0]); close(fd1[1]);
		close(fd2[0]); close(fd2[1]);
		return 1;
	}
	if(fpid == 0){		// child process
		printf("uniq process, id is %d\n", getpid());
		if(dup2(fd1[0], STDIN_FILENO) == -1){
			perror("dup2");
			return 1;
		}
		if(dup2(fd2[1], STDOUT_FILENO) == -1){
			perror("dup2");
			return 1;
		}
		close(fd1[1]);
		close(fd2[0]);
		if(execlp("/usr/bin/uniq", "uniq", NULL) == -1){
			perror("uniq");
			return 1;
		}
	}
	
	fpid = fork();
	if(fpid < 0){
		perror("fork");
		return 1;
	}
	if(fpid == 0){		// child process
		printf("wc process, id is %d\n", getpid());
		if(dup2(fd2[0], STDIN_FILENO) == -1){
			perror("dup2");
			return 1;
		}
		close(fd2[1]);
		close(fd1[0]);
		close(fd1[1]);
		if(execlp("/usr/bin/wc", "wc", "-l", NULL) == -1){
			perror("wc");
			return 1;
		}
	}
	
	close(fd1[0]);close(fd1[1]);
	close(fd2[0]);close(fd2[1]);
	wait(NULL);

	return 0;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值