linux重定向与管道

linux重定向与管道

一、背景

linux中,我们经常会用到重定向符号“>”,“<”,前者是输出重定向符号,后者是输入重定向符号。如使用who > userlist来将登陆在此系统的用户输出到userlist文件中。那么为什么who的输出结果不是显示在屏幕上而是写入到了userlist这个文件中呢?这就是linux的重定向。再者,大家也都用过管道符号“|”,如使用more /etc/passwd | grep pf,来搜索passwd中含有pf的行,也就是搜索用户名为pf的用户信息。而为什么more的输出结果会交给命令grep呢。这就是linux的管道。接下来我将通过编程来实现自己的重定向与管道。

二、一概念一原则

想要理解重定向与管道必须先要知道一个概念和一个原则。

一个概念:所有的linux工具都使用文件描述符012。这三个文件描述对应着三个数据流。0:标准输入流。1:标准输出流。2:标准错误流。标准输入流默认连接键盘终端。标准输出流默认连接屏幕终端。标准错误流默认连接屏幕终端。

一个原则:当打开一个文件时,默认为此文件按安排的文件描述符总是数组中最低可用位置的索引。

三、重定向的实现

我这里以who > userlist为例

1、方法

如果记住了一个概念与一个原则,那么想要实现重定向就并不难了。针对输出重定向来说,当一个进程从键盘终端获取输入之后进行输出时是默认的输出到文件描述符1对应的文件的。而文件描述符1默认连接的文件是/dev/tty1,也即屏幕终端(这个之前说过,在linux中每个设备都以文件形式读写,屏幕终端对应的文件是/dev/tty1)。而我想要一个进程输出的结果不写入屏幕终端的方法显然是将文件描述符1连接的文件修改一下,修改为我想要输出到的文件即可。

2、实现

实现上述方法,用系统调用close1)将文件描述符1与屏幕终端的连接中断。然后创建一个新的文件userlist,那么userlist就会因为最低可用文件描述符原则而与文件描述符1建立连接。结果如下:

linux重定向与管道_第1张图片

其中,who命令,userlist是输出命令结果的文件。当然也并不是非要输出who的结果到userlist。还可以是ps等命令。如:

linux重定向与管道_第2张图片

3.实现源码

#include

#include

#include

#include

 

int main(int ac,char *av[])

{

 if(close(1) ==-1){

   perror("close wrong!");

   exit(1);

   }

 if(creat("userlist",0644) == -1){

   perror("userlist creat failed");

   exit(1);

   }

 execlp(av[1],av[1],NULL);

 return 0;

}

四、管道的实现

我这里以who | sort为例

1、方法

管道,顾名思义,就是一个通道,可以从一个地方通向另一个地方。用在操作系统中指的是两个文件描述符之间是互通的。像是一个导电线连接着两个地方一样,当一个地方有电,另一个地方也会有电。那么,类比于文件描述符中,当一个文件描述符中有一些数据,那么另一个文件描述符中也会相应的有这些数据。而当一个有管道的进程使用fork创建一个子进程,那么这个子进程也会继承父进程有管道的事实。而且这个管道是公用管道。下面我画个示意图:

linux重定向与管道_第3张图片

012345表示文件描述符,椭圆形表示管道。可以看到文件描述符45用管道连接了起来。这时,该进程创建一个子进程。情况是这样的:

 

linux重定向与管道_第4张图片

如图所见,使用fork可以共享管道。

我在这里采取的方法是先关掉文件描述符01。然后创建管道,将01连接起来。接着创建子进程。子进程与父进程共享管道。接下来用子进程运行参数1的命令,用父进程运行参数2的命令。但别忘记在父进程中要将文件描述符1修改为连接到屏幕终端,否则将什么输出也没有。这样就完成了一个命令的结果传输成为另一个命令的输入。

2、实现

linux重定向与管道_第5张图片

这里是我的实现结果。对who输出的结果进行了排序。

3、实现源码

#include

#include

#include

#include

 

intmain(int ac,char *av[])

{

 int apipe[2],pid;

 

 close(0);

 close(1);

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

   perror("pipe wrong!");

   exit(1);

   }

 pid = fork();

 if(pid == -1){

   perror("fork wrong!");

   exit(1);

   }

 else if(pid == 0){

   execlp(av[1],av[1],NULL);

   perror("execlp wrong!");

   exit(1);

   }

 else{

   close(1);

   open("/dev/pts/0",O_WRONLY);

   execlp(av[2],av[2],NULL);

   perror("execlp wrong!");

   exit(1);

   }

}

五、总结

   重定向与管道本质上是对文件描述符的一系列操作,要牢记一个概念和一个原则。这样就能更深刻、灵活的理解与使用重定向与管道。

你可能感兴趣的:(linux系统编程)