【linux】Linux管道的原理与使用场景

news2024/11/18 13:33:36

Linux管道是Linux命令行界面中一种强大的工具,它允许用户将多个命令链接起来,使得一个命令的输出可以作为另一个命令的输入。这种机制使得我们可以创建复杂的命令链,并在处理数据时提供了极大的灵活性。在本文中,我们将详细介绍Linux管道的使用方法和实际应用。

管道的基本概念

管道(pipe)是一种特殊的文件类型,它在内存中创建一个缓冲区,用于存储一种命令的输出和另一种命令的输入。

管道的创建和使用非常简单,只需要使用|符号即可。

例如,我们可以使用ll命令列出当前目录中的所有文件,然后通过管道将这些文件的列表传递给grep命令,以搜索某个特定的文件:

$ ll | grep ooxx
-rw-rw-r-- 1 vagrant vagrant    7 Dec 21 06:07 ooxx.txt

在这个例子中,ls命令的输出成为了grep命令的输入,这就是管道的基本用法。

管道的工作原理

管道背后的主要思想是“生产者-消费者”模型,其中一个进程产生数据,而另一个进程消费这些数据。

创建管道的系统调用是pipe(),它创建了一对文件描述符:一个用于读,一个用于写。当在shell中使用管道时,shell会自动调用pipe()以及其他一些系统调用来设置进程间的数据流。

以下是管道创建和数据流动的基本步骤:

  • 创建管道:当用户在shell中输入一个包含管道的命令(如cmd1 | cmd2)时,shell会使用pipe()系统调用创建一个管道。pipe()系统调用返回两个文件描述符:一个用于管道的读端,一个用于管道的写端。

  • 创建进程:接下来,shell使用fork()系统调用创建两个子进程。每个子进程将执行命令链中的一个命令(cmd1和cmd2)。

  • 设置文件描述符:在执行命令之前,shell会对子进程的文件描述符进行操作,确保cmd1的标准输出(stdout)连接到管道的写端,而cmd2的标准输入(stdin)连接到管道的读端。这通常通过 dup2() 或 close() 系统调用来完成。

  • 执行命令:然后,shell使用exec()系统调用来替换子进程的内存空间,运行相应的命令。cmd1 进程写入数据到管道的写端,而 cmd2 进程从管道的读端读取数据。

  • 数据流动:当 cmd1 进程向管道写入数据时,这些数据被缓存在内核中,直到 cmd2 进程从管道读取它们。
    如果管道的写端没有数据可写,cmd2 进程在尝试读取时会阻塞(等待),直到有数据可读。
    如果管道的读端没有进程读取数据,cmd1 进程在写入时会收到一个 SIGPIPE 信号,通常会导致写入进程终止。

  • 清理:当两个命令都执行完毕后,shell会关闭所有打开的文件描述符,并回收子进程的资源。

通过这种方式,管道能够将不同命令的输出和输入无缝连接起来,创建一个数据处理的流水线,极大地增强了shell脚本和命令行的功能性和灵活性。

管道产生进程的演示

查看当前bash的PID:

$ echo $$
2514

使用管道连接下面的两个命令:

$  { echo $BASHPID; read a; } | { cat; read b; }
5610

我们发现5610的进程阻塞住了,在等待输入。

查看父进程生成的两个子进程的PID:

$ ps -ef|grep 2514
vagrant   5610  2514  0 08:07 pts/0    00:00:00 -bash
vagrant   5611  2514  0 08:07 pts/0    00:00:00 -bash

两个子进场的PID分别为5610(第一个命令)和5611(第二个命令)。

再来看看管道是怎么将两个进程的输入和输出连接在一起的:

5610(第一个命令)的文件描述符目录如下:

$ ll /proc/5610/fd
lrwx------ 1 vagrant vagrant 64 Dec 26 08:08 0 -> /dev/pts/0
l-wx------ 1 vagrant vagrant 64 Dec 26 08:08 1 -> 'pipe:[103565]'
lrwx------ 1 vagrant vagrant 64 Dec 26 08:08 2 -> /dev/pts/0

5610(第一个命令)的输出流连接到管道pipe:[103565]上。

5611(第二个命令)的文件描述符目录如下:

$ ll /proc/5611/fd
lr-x------ 1 vagrant vagrant 64 Dec 26 08:08 0 -> 'pipe:[103565]'
lrwx------ 1 vagrant vagrant 64 Dec 26 08:08 1 -> /dev/pts/0
lrwx------ 1 vagrant vagrant 64 Dec 26 08:08 2 -> /dev/pts/0

5611(第二个命令)的输入流连接到管道pipe:[103565]上,这样就将两个进程的输入和输出连接在一起了。

$ 和 和 BASHPID的区别

在上面的例子中,我们演示了$$$BASHPID这两个变量都能获取当前进程的ID(PID),那么他们直接有什么区别呢?

先将上面管道的的例子中的$BASHPID替换为$$执行:

$ { echo $$; read a; } | { cat; read b; }
2514

发现打印的是父进程的PID(2514),而不是子进程的PID,这是为什么呢?

$ 和 和 BASHPID的区别:

  • $$:$$的优先级高于子shell(在脚本中通过括号创建的子shell(command)或者在管道中|),在执行命令的时候会先将$$替换为父进程的PID(2514),再创建子进程执行shell。

  • ** B A S H P I D ∗ ∗ : BASHPID**: BASHPIDBASHPID的优先级低于子shell,所以在执行命令的时候会先创建子进程,然后在执行命令,这样打印的就是子进程的PID。

下面是一个例子来展示它们之间的区别

下面的例子也是同样的道理:

$ echo "PID of the current shell: $$"
PID of the current shell: 2514

$ echo "BASHPID of the current shell: $BASHPID"
BASHPID of the current shell: 2514

$ ( echo "PID of the subshell: $$"; echo "BASHPID of the subshell: $BASHPID" )
PID of the subshell: 2514
BASHPID of the subshell: 6050

在不涉及子shell的情况下,$ 和 和 BASHPID通常会返回相同的值,因为当前Bash实例就是当前shell。但是在涉及子shell的复杂脚本中,理解这两个变量之间的区别非常重要,以便正确地获取所需的PID。

管道的效率与限制

以下是管道的效率特点:

  • 内核级操作:管道的数据传输是在内核空间进行的,没有涉及用户空间和内核空间之间的数据拷贝,这使得管道非常高效。

  • 无需临时文件:管道允许直接在进程间传递数据,不需要写入到临时文件中再读取,减少了磁盘I/O操作,提高了数据处理速度。

  • 并发执行:管道连接的命令可以同时执行,不需要等待前一个命令完成后才开始下一个命令,这样可以更充分地利用CPU资源。

  • 缓冲机制:管道本身具有一定的缓冲区,这可以减少读写操作的次数,提高效率。

以下是管道的限制:

  • 单向数据流:管道是单向的,数据只能从管道的一端流向另一端。如果需要双向通信,则需要使用两个管道或其他通信机制,如套接字。

  • 固定大小的缓冲区:管道的缓冲区大小是固定的,通常取决于系统内核。一旦缓冲区满了,写操作就会阻塞,直到有进程读取数据为止。同样,如果缓冲区为空,读操作也会阻塞。

  • 数据完整性:管道不保证消息边界,如果需要传递结构化的数据,发送和接收进程需要约定数据格式或使用特定的协议来确保数据的完整性。

  • 阻塞问题:如果管道的读端没有进程读取数据,写端的进程在写入数据时将会收到 SIGPIPE 信号。如果管道的写端没有进程写入数据,读端的进程会读取到文件结束符(EOF),这可能导致进程阻塞或终止。

  • 资源限制:每个用户和系统都有打开文件描述符的数量限制,大量使用管道可能会耗尽可用的文件描述符。

  • 错误处理:管道中的错误可能不会直接传递给前一个命令。例如,如果 cmd1 | cmd2 中的 cmd2 失败了,cmd1 可能仍然在不知情的情况下继续运行,除非它试图写入更多数据到已经因为 cmd2 的终止而关闭的管道。

管道的实际应用

Linux管道在实际应用中非常广泛,可以用于各种数据处理和工作流程的构建。以下是一些常见的应用场景和例子:

  • 文本处理和过滤器:管道非常适合处理文本数据。可以使用各种文本过滤器(如grep、sed、awk等)组合起来进行文本搜索、替换、提取等操作。例如,可以通过将ls命令的输出传递给grep来搜索特定的文件:ls | grep .txt

  • 数据转换和格式化:可以使用管道将一个命令的输出传递给另一个命令进行数据转换和格式化。例如,可以使用cat命令将一个文件的内容输出到管道,然后使用tr命令将其中的大写字母转换为小写字母:cat file.txt | tr 'A-Z' 'a-z'

  • 进程监控和管理:可以使用管道来监控和管理系统中的进程。例如,可以使用ps命令获取进程列表,并将其传递给grep命令来筛选特定的进程:ps aux | grep nginx

  • 多命令串联:可以使用管道将多个命令串联在一起,形成更复杂的工作流程。例如,可以使用find命令查找特定类型的文件,并将结果传递给xargs命令来执行后续的操作:find . -name "*.txt" | xargs rm

  • 日志分析和处理:管道可以用于实时分析和处理日志数据。例如,可以使用tail命令实时监视日志文件,并将其输出传递给grep命令来筛选感兴趣的日志条目:tail -f logfile.txt | grep “error”。

  • 数据流分析和统计:可以使用管道将数据流传递给统计命令进行数据分析和统计。例如,可以使用cat命令将一个文件的内容输出到管道,然后使用wc命令统计行数、单词数和字符数:cat file.txt | wc

这只是一小部分管道的应用场景和例子,实际上,几乎任何需要将多个命令或工具组合起来进行数据处理和操作的情况下,都可以考虑使用管道。通过灵活地组合各种命令和工具,可以构建出强大而高效的数据处理流程。

结语

总的来说,Linux管道是一个非常强大的工具,它可以帮助我们在处理数据时提供极大的灵活性。通过学习和掌握管道的使用,我们可以更有效地使用Linux命令行,更好地完成各种复杂的数据处理任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1338426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是焊点保护胶?它的作用是什么

焊点保护胶是一种用于电子元件焊点和连接处的保护的特殊胶水。它主要作用是提供以下几点的保护和增强功能: 防腐蚀保护 电子元件的焊点容易受到环境中的湿度、化学物质和其他腐蚀性因素的影响。焊点保护胶能够形成一层防护膜,减少腐蚀的风险&#xff0c…

苏州科技大学计算机817程序设计(java) 学习笔记

之前备考苏州科技大学计算机(专业课:817程序设计(java))。 学习Java和算法相关内容,现将笔记及资料统一整理归纳移至这里。 部分内容不太完善,欢迎提议。 目录 考情分析 考卷题型 刷题攻略…

Typora使用PicGo+Gitee上传图片报错403 Forbidden

Typora使用PicGoGitee上传图片报错403 Forbidden Typora使用PicGoGitee上传图片,上传失败了,错误信息如下 打开PicGo的日志文件查看,可以看到错误详情如下 换了一个插件github-plus重新配置,解决了这个问题 再打开日志查看&…

vue+element+springboot实现多张图片上传

1.需求说明 2.实现思路 3.el-upload组件主要属性说明 4.前端传递MultipartFile数组与服务端接收说明 5.完整代码 1.需求说明 动态模块新增添加动态功能,支持多张图片上传.实现过程中对el-upload组件不是很熟悉,踩了很多坑,当然也参考过别的文章,发现处…

浅谈互联网架构演变

更好的阅读体验 \large{\color{red}{更好的阅读体验}} 更好的阅读体验 前言 可以将某个项目或产品的架构体系按照如下方式分层: 业务层面:项目业务体系技术层面: 数据架构:数据持久层策略应用架构:应用层的实现方式 …

HBase深度历险 | 京东物流技术团队

简介 HBase 的全称是 Hadoop Database,是一个分布式的,可扩展,面向列簇的数据库,是一个通过大量廉价的机器解决海量数据的高速存储和读取的分布式数据库解决方案。本文会像剥洋葱一样,层层剥开她的心。 特点 首先我…

Android中_Service生命周期和AMS流程的创建

Service生命周期可以结合Android生命周期分析。 Service生命周期可以从两种启动Service的模式开始讲起,分别是context.startService()和context.bindService()。 Service的生命周期与启动和绑定状态相关。当调用startService()方法启动服务时,会执行onS…

65内网安全-域环境工作组局域网探针

这篇分为三个部分,基本认知,信息收集,后续探针, 基本认知 分为,名词,域,认知; 完整架构图 名词 dwz称之为军事区,两个防火墙之间的区域称之为dwz,但安全性…

大象机器人发布万元级水星Mercury人形机器人产品系列,联结未来,一触即达!

十四五机器人产业发展规划指出机器人的研发、制造、应用是衡量一个国家科技创新和高端制造业水平的重要标志。当前,机器人产业蓬勃发展,正极大改变着人类生产和生活方式,为经济社会发展注入强劲动能。 人形机器人作为机器人产业中重要的一环&…

【nw.js】使用nw.js将html页面打包成exe免安装程序

文章目录 一、批处理zip命令(已有可跳过此步骤)二、nw.js包三、使用批处理命令打包成exe可执行文件四、使用EnigmaVB打包成免安装可独立运行的exe文件五、结束 一、批处理zip命令(已有可跳过此步骤) 下载zip,你可以到该…

连续语义分割(CSS)24种最新经典方法汇总,包含数据回放、自监督、正则化等5个细分方向

连续语义分割(CSS)是计算机视觉中的一个新兴领域,其基本任务是在某一时刻学习预测特定类别的图像分割,并在随后需要的时候连续增加学习类别的数量,同时保持对已有类别的分割能力。这个过程中需要解决的主要挑战包括灾难…

Java虚拟机知识点总结

总结黑马程序员笔记 Java运行时数据区域 可以分成线程私有的和线程共享的区域。 线程私有的区域有:虚拟机栈,本地方法栈,程序计数器 线程共享的区域有:堆,方法区(在JDK1.8中,方法区放在了本…

【验证概括 SV的数据类型_2023.12.18】

验证概括 验证的过程是保证芯片实现符合规格说明书(Specification,spec)的过程 验证的两项任务: RTL sim:前仿真,验证功能 GLS-Gate (Level Simulation):后仿真,验证功能和时序 验…

JDK 14全景透视:每个Java开发者必知的新特性

欢迎来到我的博客,代码的世界里,每一行都是一个故事 JDK 14全景透视:每个Java开发者必知的新特性 前言:switch表达式标准化Switch表达式成为正式特性的意义:如何使用Switch表达式:注意事项: ins…

【PostGIS】在Java中操作postgis——使用springboot+Maven+mybatis框架

前言: PostgreSQL15对应PostGIS安装教程及空间数据可视化 空间数据库-常用空间函数 完成PostGIS的安装与配置后,让我们来写一个Java操作postgis数据库的demo吧~ 使用工具: NavicatIDEA 一、PostGIS数据库准备 在Navicat中新建一个postgr…

前端Vue进阶

Vue进阶 当你熟悉了Vue.js的基本概念和用法后,可以继续深入学习Vue.js的进阶内容。以下是一些Vue.js的进阶主题,可以帮助你更好地理解和应用Vue.js。 组件通信 Vue.js提供了多种方式来实现组件之间的通信。除了父子组件之间的通信,还有兄弟…

python降低图像的空间分辨率——冈萨雷斯数字图像处理

原理: 降低图像的空间分辨率意味着减少图像中可见的细节,使图像变得模糊或粗糙。这可以通过减少图像的像素数量或改变像素的排列来实现。以下是一些降低图像空间分辨率的常见原理和方法: 下采样(Subsampling)&#xf…

多功能演示工具ProVideoPlayer2 mac特色介绍

ProVideoPlayer2 mac是用于大多数任何生产的首选多功能演示工具。ProVideoPlayer 2是一种动态视频播放和处理媒体服务器,可将视频映射(包括播放和实时视频输入)实时控制到一个或多个输出。包括实时效果,调度,网络同步和…

Spring中常见的Bean后处理器

Bean后处理器的作用:为Bean生命周期各个阶段提供扩展。接下来我们查看一个案例 public class TestBeanPostProcessor {public static void main(String[] args) {//该容器不存在任何Spring中的bean对象,是一个干净的容器,且提供了正常容器中…

<JavaEE> 协议格式 -- 传输层协议 TCP

目录 一、TCP协议格式长啥样? 二、TCP协议属性解释 1)源端口号/目的端口号 2)序号/确认序号 3)TCP报头长度 4)保留位 5)标志位 6)窗口大小 7)校验和 8)紧急指针…