当前位置: 首页 > 科技观察

Linux中的管道是什么?管道重定向如何工作?

时间:2023-03-12 02:05:21 科技观察

我们经常使用类似cmd0|命令1|cmd2在命令行中。其实这就是管道重定向(piperedirection),用于将一个命令的输出重定向为下一个命令的输入。那么,你真的知道它是如何工作的吗?今天让我们仔细看看。注意:本文将在多处使用术语Unix(而不是Linux),因为管道的概念起源于Unix。Linux中的管道:一般概念什么是Unix管道?Unix管道是一种IPC(进程间通信)机制,它将一个程序的输出转发到另一个程序的输入。现在,让我们用更专业易懂的语言重新解释一下:Unix管道是一种IPC(InterProcessCommunication,进程间通信)机制,它接收程序的标准输出(stdout),并通过缓冲区转发给另一个程序的标准输入(stdin)。这个描述大家应该都能看懂。请参阅下图以了解管道的工作原理:管道命令最简单的示例之一是将一些命令输出通过管道传输到grep命令以搜索特定字符串。例如,我们可以搜索名称中包含txt的文件,如下:pipe将标准输出重定向到标准输入,但不作为命令参数。非常重要的是要注意管道命令将标准输出(stdout)传递给另一个A命令的标准输入(stdin),但不是作为参数。下面我们举一个例子来说明这一点。如果我们使用不带任何参数的cat命令,它将默认从标准输入读取。请参见以下示例:$catHello,myfriend.^DHello,myfriend。在上面的示例中,cat没有任何参数地使用,因此默认情况下它将读取stdin。接下来,我写了一行文本并按Ctrl+d告诉它我完成了(Ctrl+d表示EOF或文件结尾)。然后,cat命令读取stdin,然后将我之前写的行输出到终端。现在,看看命令:echohey|cat管道右边的命令不等于cat嘿。在这里,标准输出(stdout)“hey”被缓冲并通过管道传输到cat命令的标准输入(stdin)。由于没有命令行参数,默认情况下cat会读取stdin,而stdin恰好包含某些内容(即“嘿”),因此cat会读取它并将其打印到stdout。为了演示差异,我们可以创建一个名为hey的文件并向其中添加一些文本。见下图:Linux中的管道类型Linux中的管道有两种类型:1)匿名管道,即无名管道;2)命名管道。匿名管道顾名思义,匿名管道没有名字。当您使用|时,它们由Unixshell动态创建。象征。我们通常所说的管道是指匿名管道。它使用起来非常方便,而且作为最终用户,我们不需要跟踪它的操作,shell会自动处理这一切。命名管道这一点略有不同,文件系统中确实存在命名管道。它们像普通文件一样存在,可以使用以下命令创建命名管道:mkfifopipe这将创建一个名为管道的文件,执行以下命令:$ls-lpipeprw-r--r--。1gliugliu0Aug417:23pipe注意开头的“p”,表示该文件是一个管道。现在让我们使用这个管道。如前所述,管道将一个命令的输出转发到另一个命令的输入。这就像快递服务,您可以将包裹从一个地址运送到另一个地址。所以第一步是交付包裹。echohey>pipe我们会看到没有打印回显信息,看起来像是挂了。新开一个终端,尝试读取文件:catpipe我们看看两个终端的输出,如下图所示:惊讶吗?两个命令同时完成执行。这是普通文件和命名管道的基本区别之一。在另一个进程读取管道之前,不会向管道写入任何内容。那么,为什么要使用命名管道呢?让我们来看看。命名管道不占用磁盘上的任何内存。如果我们执行命令du-spipe,我们会看到它不占用任何空间。这是因为命名管道就像从内存缓冲区读取和写入的端点。写入命名管道的任何内容实际上都存储在一个临时内存缓冲区中,当从另一个进程执行读取时,该缓冲区会被刷新。节省IO,因为写入命名管道意味着将数据存储到内存缓冲区中,因此如果涉及涉及大文件的操作,则会大大减少磁盘I/O。两个不同进程之间的通信使用命名管道有效地实时获取另一个进程的事件输出。因为读取和写入同时发生,所以没有延迟。底层管道理解(针对高级用户和开发人员)接下来我们更深入地讨论管道,以及具体的实现。这些需要对以下内容有基本的了解:C程序如何工作;什么是系统调用;什么是流程;什么是文件描述符。我们不会详细介绍这些概念,只讨论管道相关的内容。对于大多数Linux用户,可以选择性阅读以下内容。为了进行编译,本文末尾提供了一个示例makefile。当然,这只是用于说明的伪代码。请参见以下程序://pipe.c#include#include#include#include#includeexterninterrno;intmain(){signedintfd[2];pid_tpid;staticcharinput[50];staticcharbuf[50];pipe(fd);if((pid=fork())==-1){int错误=错误号;perror("分叉失败");退出(错误);}if(pid){关闭(fd[1]);读取(fd[0],buf,50);printf("从孩子那里读到的消息:%s\n",buf);}else{close(fd[0]);printf("请输入来自父母的信息:");for(inti=0;(input[i]=getchar())!=EOF&&input[i]!='\n'&&i<49;i++);写(fd[1],输入,50);exit(0);}return0;}在第16行,我使用pipe()函数创建了一个匿名管道,传递了一个长度为2的有符号整数数组。这是因为管道只是两个无符号整数的数组,代表两个文件描述符。一种用于写作,一种用于阅读。它们都指向内存中的缓冲区位置,通常为1mb。这里我将变量命名为fd。fd[0]是输入文件描述符,fd[1]是输出文件描述符。在这个程序中,一个进程向fd[1]文件描述符写入一个字符串,另一个进程从fd[0]文件描述符读取。命名管道也是如此,使用命名管道(而不是两个文件描述符),您可以从任何进程打开文件并像处理其他文件一样操作它。同时,应牢记管道的特性。下面是一个示例程序,它做的事情与前面的程序相同,但它创建的不是匿名管道,而是命名管道://fifo.c#include#include#include#include#include#include#include#includeexterninterrno;#definefifo"npipe"intmain(void){pid_tpid;staticcharinput[50];staticcharbuf[50];signedintfd;mknod(fifo,S_IFIFO|0700,0);if((pid=fork())<0){内部错误=错误号;perror("分叉失败");退出(错误);}if(pid){fd=open(fifo,O_RDONLY);读取(fd,buf,50);关闭(fd);printf("输出为:%s",buf);删除(先进先出);退出(0);}else{fd=open(fifo,O_WRONLY);for(inti=0;(input[i]=getchar())!=EOF&&input[i]!='\n'&&i<49;i++);写(fd,输入,strlen(输入));关闭(fd);exit(0);}return0;}在这里,我使用mknod系统调用来创建命名管道。如您所见,虽然管道在完成时被删除,但您可以通过简单地打开和写入本示例中的npipe文件而不使用它来轻松地在不同进程之间进行通信。其实在现实中,我们并不一定要创建两个管道来实现双向通信,匿名管道就是这样。下面是一个简单的Makefile的源代码示例(只是示例),与前面的程序(分别是pipe.c和fifo.c)放在同一目录中。CFLAGS?=-Wall-g-O2-WerrorCC?=clangbuild:$(CC)$(CFLAGS)-opipepipe.c$(CC)$(CFLAGS)-ofifofifo.cclean:rm-rfpipefifo上面以上就是本次分享的关于Unix管道的全部内容,欢迎讨论。