如何熟悉Linux的管道?

Linux基础

1 基础知识

1.1 管道的介绍

– 管道为Pipeline的翻译
– 管道是类Unix系统使用极其广泛的进程通讯机制
– 管道是将标准输入和标准输出链接起来的进程
– 管道把前一个进程的输出作为下一个进程的输入
– 管道由道格拉斯·麦克罗伊为Unix命令行而发明
– 管道因为与物理管道相似而得名

1.2 管道的分类

1.2.1 匿名管道

– 匿名管道是计算机进程间的一种先进先出通讯机制(不支持异步读写操作)
– 匿名管道两个可以实现全双工通讯
– 匿名管道可由父进程创建,然后由其创建的多个子进程继承
– 匿名管道由于没有名称,所以只能用于本地计算机通讯不能用于网络通讯
– 匿名管道生存期不超过创建管道进程的生存期

1.2.2 命名管道

– 命名管道是计算机进程间的一种先进先出通讯机制(不支持异步读写操作)
– 命名管道是类Unix系统传统管道(匿名管道)的扩展
– 命名管道生存期可以与操作系统运行期一样长

1.2.3 网络管道

– 命令“netcat”和“socat”可以将管道链接到TCP/IP套接字

2 最佳实践

2.1 匿名管道的使用

2.1.1 简单的使用

ls /etc/ | grep init.d

范例解析,
前进程“ls”列出“/etc”目录的内容
后进程“grep”根据关键字“init.d”过滤前进程列表后得到想要的结果

2.1.2 合并错误流

ls cmdschool.org | grep "No such file or directory"

上例,命令“ls”找不存在的文件而报错(错误流),如想用管道传递错误会失败,正确方式是把标准错误流合并到标准输出流中再传递,详细如下,

ls cmdschool.org 2>&1 | grep "No such file or directory"

2.1.3 Pipemill

ls -l /tmp/ | while read var1 var2 var3 var4 var5 var6 var7 var8; do
        echo "$var1 $var2 $var3 $var4 $var5 $var6 $var7 $var8"
done

注:Pipemail中文翻译为“制管机”,用法是管道配合“while”循环以及“read”读取管道传递的多个变量并利用。

2.2 命名管道的使用

2.2.1 从命令管道中压缩数据

mkfifo my_pipe

以上创建命名管道“my_pipe”,然后我们使用gzip压缩传给管道“my_pipe”的数据,范例如下,

gzip -9 -c < my_pipe > out.gz

然后,我们使用另一个shell独立地发送数据到管道“my_pipe”

cat file > my_pipe

使用完成后,我们可以使用如下命令清理命名管道,

rm my_pipe

2.2.2 解压数据到命名管道

mkfifo -m 0666 /tmp/myPipe
gzip -d < file.gz > /tmp/myPipe

然后从命令管道中读取,

LOAD DATA INFILE '/tmp/myPipe' INTO TABLE tableName;

2.2.3 循环获取命名管道

mkfifo -m 0666 /tmp/myPipe

以上创建命令管道,然后使用如下循环监视命令管道,

#!/bin/bash

myFifo="/tmp/myPipe"
while true; do
        if read line; then
                echo $line
        fi
        sleep 0.001s
done < "$myFifo"

然后,我们用另外一个shell往命名管道中写入数据可以观察到效果,

ls /tmp/* >> /tmp/myPipe

注:使用“sleep”语句防止CPU过高,请根据实际情况调整暂停时间。

2.2.4 命名管道控制线程高并发执行

#!/bin/bash

thread=3

fifoFile="/tmp/$$.fifo"
mkfifo $fifoFile
exec 9<>$fifoFile
rm -f $fifoFile

for ((i=0;i<$thread;i++)); do
    echo >&9
done

for ((;;)); do
    read -u 9
    {
        echo "$$ infinite loops [ hit CTRL+C to stop]"
        sleep 1s
        echo >&9
    } &
done
wait
exec 9>&-

脚本解析如下,
– 变量“thread”,定义每次并发的线程数
– 命令“mkfifo”,创建命名管道文件(命名管道具有先进先出的特性,且每一行读取后就自动删除)
– 命令“exec”,即第一个执行使用文件描述符(FD)“9”关联创建的管道问题,后面可以使用文件描述符直接访问
– 命令“rm”,删除创建的命名管道文件(不删除也可以,非必须操作)
– 命令“for”,即第一个循环根据变量“thread”的定义通过文件描述符往管道中写入相应的空行,范例为3个空行
– 命令“for”,即第二个循环无限地执行循环内的代码
– 命令“read”,配合“{}&”并发地读取命名管道中每行,由于范例管道只有3行,所以3行同时读取后只能等待新的写入
– 命令“echo”,即第一个打印代表执行代码,范例只输出“脚本名称”加“infinite loops [ hit CTRL+C to stop]”提示
– 命令“sleep”,暂停1秒(可以不暂停),范例暂停的目的只为脚本演示效果明显且易于理解
– 命令“echo”,即第二个打印空行到命名管道(透过关联的文件描述符),否则管道中没有新行则命令“read”只能等待
– 命令“wait”,等待前面的命令“for”完全结束
– 命令“exec”,即第二个执行解除文件描述符“9”和变量“fifoFile”定义的管道文件的关联
注:
– 文件描述符可以使用的数量取决于Linux系统“ulimit”的定义设置(可以修改,理论上可以定义无限)
– 命令“exec”原则上支持关联“0~9”的文件描述符,但由于“0~2”被标准输入、标准输出和标准错误流占用因此无法使用。

参阅文档
==================

管道
———-
https://zh.wikipedia.org/wiki/%E7%AE%A1%E9%81%93_(Unix)

匿名管道
————
https://zh.wikipedia.org/wiki/%E5%8C%BF%E5%90%8D%E7%AE%A1%E9%81%93

命令管道
—————
https://zh.wikipedia.org/wiki/%E5%91%BD%E5%90%8D%E7%AE%A1%E9%81%93

没有评论

发表回复

Linux基础
如何配置RHEL 8.x OpenSSH客户端登录自动过期?

1 前言 一个问题,一篇文章,一出故事。 基于服务器安全,笔者需要让OpenSSH客户端在10分钟内 …

Linux基础
如何安装部署SentinelOne EDR?

1 基础知识 1.1 软件公司介绍 SentinelOne,Inc.是一家在纽约证券交易所上市的美国 …

Linux基础
如何配置Ext4的磁盘配额?

1 基础知识 1.1 Disk Quota的概念 Disk Quota用于合理分配有限的磁盘使用空间 …