0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

管道和重定向的真实含义(定义)是什么呢?

Linux爱好者 来源:TOMORROW 作者:TOMORROW 2020-12-11 16:26 次阅读

对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! "); 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! "); 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 来找到管道读端所对应内存缓冲区。

从而实现了通过标准输入来读取管道的数据,也可以说是,将管道的读端重定向到了标准输入。管道的写端与标准输入的关系也与此类似,此处不再赘述。

3fac420e-2eb2-11eb-a64d-12bb97331649.png

调用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

3fceea20-2eb2-11eb-a64d-12bb97331649.png

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

3ff9e090-2eb2-11eb-a64d-12bb97331649.png

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 函数
    +关注

    关注

    3

    文章

    4299

    浏览量

    62350
  • 管道
    +关注

    关注

    3

    文章

    145

    浏览量

    17923
  • 代码
    +关注

    关注

    30

    文章

    4733

    浏览量

    68277

原文标题:Shell:管道与重定向

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    嵌入式 学习-飞凌嵌入式ElfBoard ELF 1板卡-shell脚本编写之输入输出重定向

    shell脚本编写之输入输出重定向shell输出重定向通常是指将执行命令的输出信息从默认的标准输出(即当前终端)重新定向到指定文件中。输入重定向通常是指将命令所需的输入数据的来源,从标
    发表于 09-24 10:06

    飞凌嵌入式ElfBoard ELF 1板卡-shell脚本编写之输入输出重定向

    shell输出重定向通常是指将执行命令的输出信息从默认的标准输出(即当前终端)重新定向到指定文件中。输入重定向通常是指将命令所需的输入数据的来源,从标准输入(即当前终端)更改为从指定文件中获取。输出
    发表于 09-23 10:23

    重定向了fputc及putchar函数,但printf没有输出,为什么?

    重定向了fputc及putchar函数,但printf没有输出 删除了drivers/drv_uart.c drv_uart.h 删除了文件rt-thread\\components
    发表于 07-18 07:44

    esp32c3能不能将串口打印函数重定向到自己软件模拟的uart上?

    模拟uart,用于打印日志;请问这种做法可以实现吗?可以将打印函数重定向到该模拟uart吗?如果可以,麻烦指导一下重定向需要修改哪几个函数? ps:打印的函数主要涉及到printf
    发表于 06-20 06:32

    请问ESP32C3如何重定向控制台串口?

    软件环境:esp-idf v4.4 硬件环境:esp32c3 问题描述:需要将控制台输出重定向到 UART1(RX: GPIO4,TX:GPIO5),UART0 用来做上下位机通信。 按照这个链接
    发表于 06-07 08:12

    请问如何将printf使用的stdout重定向到asclin?

    /v4.9.3.0-infineon-1.0/docs/userguide.pdf 第 406 页中关于 printf 的唯一说明是 stdout 重定向到模拟 io 调试器。 当然,您可以使用 Ifx_Console_print,但我想知道是否可以通过标准库来实现。
    发表于 06-03 06:48

    芯海通用 MCU应用笔记 :在 IAR 及 MDK 开发环境下使用 printf 函数重定向移植差异指南

    对 printf 函数支持的差异。并在本应用笔记结尾处给出可以一键移植到 Keil、IAR8.x、IAR9.x 版本下的通用重定向代码。 Keil 和 IAR 都是常用的开发工具 IDE,在实际项目开发
    发表于 05-16 11:56

    求助,关于HAL下的printf重定向输出疑问求解

    (1)网上查了使用printf重定向,串口输出,函数如下,使用HAL_UART_Transmit函数。 int fputc(int ch,FILE *f) { uint8_t temp[1
    发表于 05-10 06:04

    STM8S如何在STVD环境下重定向printf函数实现UART简化输出?

    1. AS the title, who can share your code in STVD?NOT in IAR,,,thanks a lot. 2. 目前困在STVD环境下,不能重定向
    发表于 04-30 08:29

    STM32CubeIDE中打印重定向报错怎么解决?

    HAL_UART_Transmit( huart1 , (uint8_t *) ch, 1, 0xFFFF);报错 printf重定向 报错../Core/Src/main.c:42:21: error: \'huart1\' undeclared 已添加stdio.h头文件。
    发表于 04-03 07:33

    H7平台如何重定向sqrtf函数到RAM中运行?

    如题,H7平台如何重定向sqrtf函数到RAM中运行,这个函数是库函数,不能使用__ramfunc前缀,有什么方法或是例程,网上找了很多icf配置的方法,都不行,要不就是只放置到RAM地址,不能程序
    发表于 03-27 06:40

    将动态指示段重定向到单独的LED

    有时,除了数字指示器之外,还需要单独的 LED。它们可以连接到微控制器的单独引脚,但您也可以节省引脚。如果数字指示器具有从未使用过的段(例如,右边数字中的一个点),则可以将它们重定向到外部 LED。
    发表于 02-02 16:49 519次阅读
    将动态指示段<b class='flag-5'>重定向</b>到单独的LED

    2分钟搞懂输出重定向

    视频最后我们通过重定向把标准输出写到了文件中,但是错误输出还是留在了屏幕上。
    的头像 发表于 01-15 16:41 521次阅读

    电子和光子的定义含义和区别

    光子和电子是两种基本的量子力学粒子,但它们具有完全不同的性质。光子是一-种作为 能量载体的基本粒子,但电子是- -种亚原子粒子,存在于所有原子中。我们将了解电子和光子的定义含义和区别。
    的头像 发表于 12-01 10:28 2610次阅读
    电子和光子的<b class='flag-5'>定义</b>、<b class='flag-5'>含义</b>和区别

    IAR下手动拷贝自定义程序段到RAM中执行的方法分享

    在痞子衡旧文 《IAR下RT-Thread工程自定义函数段重定向失效分析》 里,我们知道 IAR 链接器处理自定义程序段重定向是有一些限制的,只要用户重写了底层 __low_level
    的头像 发表于 11-21 09:38 1850次阅读
    IAR下手动拷贝自<b class='flag-5'>定义</b>程序段到RAM中执行的方法分享