浅谈Linux Shell的管道与重定向

对shell有一定了解的人都知道,管道和重定向是 Linux 中非常实用的 IPC 机制。
在shell中,我们通常使用符合‘|’来表示管道,符号‘>’和‘<’表示重定向。
那么管道和重定向的真实含义(定义)又是什么呢?
管道
管道的定义
管道就是一个进程与另一个进程之间通信的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入。
它是半双工运作的,想要同时双向传输需要使用两个管道。
管道又可以分为匿名管道和命名管道,而shell中使用到的是匿名管道,所以本文仅描述匿名管道。
例如命令ls | grep main.c,使用了管道来连接了两条命令来执行,能够快速地让我们知道当前目录下是否有 main.c 文件。
管道的本质是内存中的缓冲区,可以看作是打开到内存中的文件。
所以需要使用两个文件描述符来索引它,一个表示读端,一个表示写端。
并且规定,数据只能从读端读取、只能往写端写入。
创建管道
使用函数pipe()可以创建匿名管道,需要包含头文件 unistd.h,示例代码:
int fd[2];
pipe(fd);
首先创建一个 2 个元素的整型数组,然后将该数组作为pipe()的参数,pipe()执行成功后,数组元素 fd[0]的值就会变成所创建的管道的读端的文件描述符,fd[1]就会变成写端的文件描述符。
至此管道就算创建成功了。
把管道作为标准输入输出
管道创建成功后,就可以直接使用 read()和 write()函数对管道进行数据的读写。
而因为shell中都是使用标准输入输出对管道进行读写的,例如ls | grep main.c就是将 ls 的标准输出写到了管道写端,而 grep 的标准输入则从管道读端读取,所以本文也只描述此方法。
示例代码如下:
int fd[2];
pipe(fd);
pid=fork();
if(0==pid) //execute next command in child process
{
dup2(fd[0],0);//redirect standard input to pipe(read)
close(fd[0]);
close(fd[1]);
if(0!=execvp(cmd0[0],cmd0))
printf("No such command!\n");
exit(EXIT_SUCCESS);
}
else //execute current command in current process
{
dup2(fd[1],1);//redirect standard output to pipe(write)
close(fd[0]);
close(fd[1]);
if(0!=execvp(cmd1[0],cmd1))
printf("No such command!\n");
exit(EXIT_SUCCESS);
}
首先是创建一个管道,然后创建子进程,子进程会继承这一个管道,也就保证了父进程与子进程操作的是同一个管道(管道的继承与普通变量不同)。
如果我们希望在子进程中执行管道的读端的程序例如ls | grep main.c中的grep main.c;在父进程中执行管道的写端的程序,例如ls | grep main.c中的ls。
在子进程中,先调用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 资源覆盖或者重新初始化。文件重定向
文件重定向
其实与上面管道重定向到标准输入输出很类似,甚至可以直接采用上面所说的方法来实现。但是此处将讲述一种更加简洁的方法实现。
实例代码如下:
char fileName[20]="out.txt";
freopen(fileName,"w",stdout);//redirect stdout to fileName
以上两行简单的代码就实现了,将该进程的标准输出重定向到了文件 out.txt ,甚至一行就可以实现。
执行以上代码后,当前进程的所有标准输出,也就是 printf()之类的输出全都会被写到文件 out.txt,显示屏将不会有输出。
而将进程的标准输入重定向到文件 in.txt 的代码如下:
char fileName[20]="in.txt";
freopen(fileName,"r",stdin);//redirect stdin to fileName

其中的核心函数就是freopen():

原文地址:https://mp.weixin.qq.com/s/o7d56SSJurXiyCLjozf4-A
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://www.juheyunku.com/jiaob/shell/8041.shtml
相关文章
热门TAG
命令 外链 企业网站 白帽 php 织梦教程 dedecms修改内容 javascript 织梦 功能 标签 调用 详解 技巧 权重 服务器 网站流量 Dedecms 织梦cms HTML tags标签 python jquery教程 jquery windows 蜘蛛 搜索引擎 网站收录 JSP 实例解析最新文章
-
PHP生成奖状
时间:2021-01-06
-
python实现输入五个数并求
时间:2021-01-06
-
php检测网站是否正常打开
时间:2021-01-05
-
python怎么右对齐
时间:2021-01-05
-
Python3爬虫入门之Python3的安
时间:2021-01-05
-
如何用PHP接收http请求头信
时间:2021-01-05
-
数据库怎么连接用php写的
时间:2021-01-05
-
php后缀怎么打开
时间:2021-01-05
热门文章
-
解析shell字段分隔符的用法(图文)
时间:2020-12-22
-
Python3爬虫进阶:MongoDB存储(非关系型数
时间:2020-12-29
-
如何在Linux或者UNIX下调试Bash Shell脚本
时间:2020-12-22
-
关于php中匿名函数与回调函数的详解
时间:2020-12-29
-
php文档怎么打开
时间:2020-12-29
-
php检测网站是否正常打开
时间:2021-01-05
-
PHP PHP_EOL 换行符
时间:2020-12-29
-
python实现输入五个数并求平均值
时间:2021-01-06
-
浅谈Linux Shell的管道与重定向
时间:2020-12-23
-
如何检测Django是否安装成功
时间:2020-12-29
