当前位置: 首页 > Linux

Shell:管道和重定向

时间:2023-04-06 22:24:01 Linux

对shell有一定了解的人都知道,管道和重定向是Linux中非常实用的IPC机制。在shell中,我们通常使用字符'|'代表管道,符号'>'和'<'代表重定向。那么管道和重定向的真正含义(定义)是什么?管道的定义管道是一个进程与另一个进程之间的通信通道,通常用于将一个进程的输出通过管道连接到另一个进程的输入。它以半双工方式运行,需要使用两条管道同时在两个方向上传输。管道分为匿名管道和命名管道,匿名管道在shell中使用,所以本文只介绍匿名管道。例如,命令ls|grepmain.c使用管道连接两个命令执行,可以快速让我们知道当前目录下是否有main.c文件。管道的本质是内存中的一个缓冲区,可以看做是一个打开到内存中的文件。所以需要用两个文件描述符来索引它,一个用于读端,一个用于写端。并且规定数据只能从读端读取,只能写入到写端。创建管道使用函数pipe()创建匿名管道,需要包含头文件unistd.h,示例代码:intfd[2];pipe(fd);先创建一个2个元素的整型数组,然后将该数组作为pipe()的参数,pipe()执行成功后,数组元素fd[0]的值将成为pipe()的读端的文件描述符创建的管道,fd[1]将成为写端的文件描述符。至此,管道创建成功。管道作为标准输入输出管道创建成功后,就可以直接使用read()和write()函数在管道上读写数据了。又因为shell使用标准输入输出来读写管道,例如ls|grepmain.c将ls的标准输出写到管道的写端,grep的标准输入从管道的读端读取,所以本文也只介绍这种方法。示例代码如下:intfd[2];pipe(fd);pid=fork();if(0==pid)//在子进程中执行下一条命令{dup2(fd[0],0);//将标准输入重定向到pipe(read)close(fd[0]);关闭(fd[1]);if(0!=execvp(cmd0[0],cmd0))printf("没有这样的命令!n");exit(EXIT_SUCCESS);}else//在当前进程中执行当前命令{dup2(fd[1],1);//重定向标准输出到管道(write)close(fd[0]);关闭(fd[1]);if(0!=execvp(cmd1[0],cmd1))printf("没有这样的命令!n");exit(EXIT_SUCCESS);}先创建管道,再创建子进程,子进程会继承这个管道,同时保证父进程和子进程在同一个管道上操作(管道的继承不同于普通变量)。如果我们想在子进程中执行管道读端的程序,比如grepmain.cinls|grepmain.c;在父进程的管道写端执行程序,比如lsinls|grepmain.c.在子进程中,首先调用dup2(fd[0],0);此函数将标准输入文件描述符0指向管道的读取端。文件描述符本质上是一个非负整数,通常是一个小整数;它是一个索引,通过它可以找到相应的文件。例如,标准输入、标准输出和标准错误的文件描述符默认为0、1和2。当进程需要从标准输入读取数据时,会通过0索引找到标准输入对应的内存缓冲区来读取数据。假设此时管道读端文件描述符为3,写端文件描述符为4。调用dup2(fd[0],0)实际上是将文件描述符3指向的文件表项赋值给文件描述符0,而文件描述符0是进程默认的标准输入。所以此时,当进程需要从标准输入读取数据时,进程会使用文件描述符0去寻找管道读端对应的内存缓冲区。这样通过标准输入读取管道的数据,也可以说是将管道的读取端重定向到标准输入。管道写入端与标准输入的关系也类似,这里不再赘述。调用dup2(fd[0],0)后,还需要调用close()函数关闭管道的原始文件描述符。关闭意味着文件描述符3和4不再索引到管道或其他文件,也就是说此时无法使用read函数从文件描述符3读取管道的数据,这并不意味着关闭管道。完成管道的设置后,就可以通过exec函数族执行外部命令了。需要注意的是,调用exec族函数不会覆盖或重新初始化管道等IPC资源。文件重定向文件重定向其实和上面的管道重定向到标准输入输出非常相似,甚至可以直接用上面说的方法实现。但是这里将描述更简洁的方法实现。示例代码如下:charfileName[20]="out.txt";freopen(fileName,"w",stdout);//redirectstdouttofileName以上两行简单代码实现,标准输出进程的重定向指向文件out.txt,一行即可实现。上述代码执行后,会将当前进程的所有标准输出,即printf()等输出写入out.txt文件中,显示器上不会有任何输出。将进程的标准输入重定向到文件in.txt的代码如下:charfileName[20]="in.txt";freopen(fileName,"r",stdin);//将stdin重定向到fileName的核心函数是freopen():转自:TOMORROW来源:https://www.tomorrow.wiki/arc...