Linux Shell Pipeline

2209 字
11 分钟
Linux Shell Pipeline

Linux管道符的知识点和使用#

先记住一句话核心: 管道符号 |,作用是:把左边命令打印出来的内容,直接交给右边命令去处理。 Linux 一切皆文本,管道就是文本传送带,把前一个工具的结果,传给下一个工具。

1. 管道的底层原理#

1.1 三大输出流#

Linux 每个命令运行时,都有 3 个数据流:

  1. 标准输入 stdin:命令读取的内容(好比人的耳朵,接收数据)

  2. 标准输出 stdout:命令正常打印的内容(好比嘴巴,输出内容)

  3. 标准错误 stderr:命令报错的红色错误信息

1.2 管道规则#

  1. 只转发 标准输出 (stdout)
  2. 默认不转发 错误信息 (stderr)
  3. 格式固定:
Terminal window
命令1 | 命令2 | 命令3

数据流向: 命令 1 打印的内容 → 自动变成 命令 2 的输入 → 命令 2 处理完 → 传给命令 3

2. 基础示例#

2.1 示例一#

Terminal window
ls -la | grep "txt"
  1. ls -la:列出当前文件夹所有文件 + 详细信息(这是左边输出)

  2. |:把上面列出的所有内容,传给右边

  3. grep "txt":筛选出包含 txt 字符串的行

2.2 示例二#

Terminal window
ps aux | grep python | wc -l
  1. ps aux:列出系统所有正在运行的进程

  2. 第一层|:全部进程信息传给 grep

  3. grep python:只筛选出和 python 相关的进程

  4. 第二层|:筛选后的内容传给 wc

  5. wc -l统计行数(也就是统计 python 进程数量)

3. 进阶:文本流水线#

3.1 错误日志筛选 + 去重#

Terminal window
cat /var/log/syslog | grep "ERROR" | sort | uniq

分步拆解:

  1. cat /var/log/syslog:读取系统日志文件全部内容

  2. grep "ERROR":只保留包含 ERROR 的错误日志

  3. sort:把日志内容按字母 / 时间排序

  4. uniq:去掉完全重复的日志行

3.2 统计每种错误出现次数#

Terminal window
cat /var/log/syslog | grep "ERROR" | sort | uniq -c | sort -nr

新增参数解释:

  • uniq -c:去重 + 在每行前面加上出现次数

  • sort -nr

    • -n:按数字排序

    • -r:倒序(错误最多的排最上面)

4. 管道 + xargs#

4.1 为什么需要 xargs?#

  • 管道 | 传递的是内容(文本),当做「输入」

  • 很多命令(rm、mkdir、curl)不接收文本输入,只接收「参数」

  • xargs 作用:把管道传过来的文本,转换成 命令的参数

4.2 示例#

4.2.1 删除所有 .log 文件#

Terminal window
find . -name "*.log" | xargs rm

拆解:

  1. find . -name "*.log":找出当前目录下所有后缀为 .log 的文件,打印出来

  2. xargs rm:把上面找到的文件名,一个个当成 rm 的参数 等价于:rm 日志1.log 日志2.log ...

4.2.2 批量访问网址#

Terminal window
cat urls.txt | xargs -P 4 -I {} curl -s {}

参数:

  • -P 4:同时开 4 个进程,并行执行

  • -I {}:用 {} 代替每一行内容

  • curl -s {}:静默访问每一个网址

5. 进程替换 <() 命令#

5.1 核心作用#

有些命令不支持管道,就用 <命令输出伪装成临时文件

Terminal window
diff <(cat file1.txt) <(cat file2.txt)
  • diff:对比两个文件差异
  • <(cat file1.txt):把 file1 内容,假装成一个文件

*等价写法(管道版):

Terminal window
cat file1.txt | diff - <(cat file2.txt)

这里的 - 代表:读取管道传来的stdout的内容

5.2 进程替换与文件重定向#

方式语法本质使用场景
进程替换cat <(cmd)将命令输出作为文件路径传入需要文件名参数时
输入重定向cat < filecmd < file将文件内容作为stdin从文件读取输入
  • 进程替换 <(...)
Terminal window
# 将命令输出伪装成文件,传给需要文件参数的命令
cat <(echo "hello world")
# 等价于: cat /dev/fd/63 (bash创建的临时管道文件描述符)
# 实际应用:对比两个命令输出
diff <(ls dir1) <(ls dir2)
# 写入文件(通过 cat 中转)
cat <(echo "content") > output.txt

原理:Bash 创建命名管道(FIFO)或 /dev/fd 文件,让 cat 以为是普通文件。

  • 输入重定向 <
Terminal window
# 从文件读取,写入另一个文件(相当于复制)
cat < input.txt > output.txt
# 等价于
cat input.txt > output.txt
# 结合 Here Document
cat << 'EOF' > output.txt
line 1
line 2
EOF

6. 标准错误管道处理#

6.1 默认问题#

管道只传正常输出,报错信息会直接打印屏幕,不走管道。

6.2 两个核心数字#

  • 1 = 标准输出(正常内容)

  • 2 = 标准错误(报错内容)

6.3 示例#

6.3.1 屏蔽错误#

Terminal window
find /root 2>/dev/null | grep "file"
  • 2>/dev/null把错误信息丢进null设备,直接删除

  • 只有正常搜索结果进入管道被 grep 筛选

6.3.2 错误也走管道#

Terminal window
find /root 2>&1 | grep "Permission"
  • 2>&1:把 错误流 (2) 合并到 正常输出流 (1)

  • 此时正常内容 + 报错内容全部进入管道,可以筛选权限报错

7. 三通阀(tee命令)#

7.1 作用#

一份数据两用

  1. 屏幕上正常显示

  2. 同时保存到文件

7.2 基础用法#

Terminal window
cat file.txt | tee backup.txt | grep "keyword"

流程:

  1. 读取 file.txt

  2. tee backup.txt

    • 复制一份内容存入 backup.txt

    • 同时把内容继续往后传给管道

  3. 最后 grep 筛选关键词

7.3 追加写入#

Terminal window
echo "新内容" | tee -a log.txt
  • -a:append 追加,不会删掉文件原有内容

8. 流式编辑器(sed命令)#

这个可以修改前端管道的内容,然后传递给后端的管道,比如cmd_1 | sed [opts] 'cmd' | cmd_2

8.1 基础用法#

Terminal window
sed [opts] 'cmd' 文件
sed [opts] -e 'cmd_1' -e 'cmd_2' 文件
  • 基础示例 (将每行第一个匹配的foo替换为bar)
Terminal window
sed 's/foo/bar/' file
  • ori
foo is great
another foo here foo
no match here
foofoo test
  • dest
bar is great
another bar here foo
no match here
barfoo test

8.2 核心命令#

8.2.1 替换(s)#

Terminal window
# 基本替换:每行第一个匹配
sed 's/foo/bar/' file
# 全局替换(g):每行所有匹配
sed 's/foo/bar/g' file
# 替换第 N 个匹配
sed 's/foo/bar/2' file # 替换每行第 2 个
sed 's/foo/bar/2g' file # 从第 2 个开始,替换后面所有
# 使用分隔符(当替换路径等含/的内容时)
sed 's#/usr/local#/opt#g' file # 用 # 代替 /
sed 's|/home/user|/data|g' file # 用 | 代替 /

8.2.2 删除(d)#

Terminal window
# 删除指定行
sed '3d' file # 删除第 3 行
sed '1,5d' file # 删除 1-5 行
sed '$d' file # 删除最后一行
# 删除匹配行
sed '/pattern/d' file # 删除含 pattern 的行
sed '/^#/d' file # 删除注释行(以#开头)
sed '/^$/d' file # 删除空行

8.2.3 打印(p)与静默(-n)#

Terminal window
# 默认 sed 会打印所有行,p 会额外打印匹配行(导致重复)
sed '/pattern/p' file # 匹配行出现两次
# -n 静默模式,只打印指定内容
sed -n '/pattern/p' file # 只打印匹配行
sed -n '5,10p' file # 打印 5-10 行(类似 head/tail)
sed -n '1~2p' file # 打印奇数行(从1开始,步长2)

8.2.4 插入、追加、修改(i/a/c)#

Terminal window
# i:行前插入
sed '3i\This is new line' file
# a:行后追加
sed '3a\This is new line' file
# c:替换整行
sed '3c\Replace line 3' file
# 匹配后操作
sed '/pattern/a\New line after match' file

8.3 常用选项#

选项作用
-i原地修改文件(in-place)
-i.bak原地修改并备份原文件为 .bak
-n静默模式,配合 p 使用
-e多命令连接
-r使用扩展正则(ERE),免转义
-E-r(BSD/macOS 风格)

8.4 实用组合示例#

Terminal window
# 1. 原地修改文件(危险操作,建议先备份)
sed -i 's/localhost/127.0.0.1/g' config.conf
# 2. 删除文件中的 Windows 换行符 (^M)
sed -i 's/\r$//' file.txt
# 3. 提取特定行范围到另一个文件
sed -n '100,200p' log.txt > extracted.txt
# 4. 多命令组合
sed -e 's/foo/bar/g' -e 's/hello/hi/g' file
# 5. 从管道读取(无输入文件)
cat file | sed 's/foo/bar/g'
# 更优写法(避免无用猫)
sed 's/foo/bar/g' < file
# 6. 复杂:删除空行和注释,提取有效配置
sed '/^#/d; /^$/d' config.ini
# 7. 使用扩展正则(更简洁)
sed -r 's/(foo|bar)/baz/g' file # 无需转义 ()

8.5 注意事项#

注意点说明
-i 无备份风险sed -i 直接修改,建议先用 sed '' file 测试
正则转义基础正则中 ()+?{} 需转义,用 -r 可免转义
macOS 差异BSD sed 要求 sed -i '' 's///' file(必须给备份后缀)
单引号优先避免 shell 提前展开变量,需要变量时用双引号

9. 匿名管道 和 命名管道#

9.1 匿名管道 |#

  • 临时生效,命令结束就消失

  • 只能一条命令行里多个命令连用

9.2 命名管道 FIFO (好玩)#

可以跨两个终端、跨进程传数据

Terminal window
# 1. 创建一个管道文件
mkfifo mypipe
# 2. 第一个终端:往管道写数据(后台运行 &)
echo "测试数据" > mypipe &
# 3. 第二个终端:读取管道数据
cat < mypipe

10. 实用指令组合#

  1. 看文件最后 100 行 + 实时过滤错误
Terminal window
tail -f 日志文件.log | grep error
  1. 统计当前目录所有文件后缀数量
Terminal window
find . -type f | sed 's/.*\.//' | sort | uniq -c
  1. 查看目录内容并分页
Terminal window
ls -la | less

11. 结尾#

没了喵,谢谢欣赏

gopher
gopher

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Linux Shell Pipeline
https://blog.tuf3i.cc/posts/linux-pipeline/
作者
TuF3i
发布于
2026-04-18
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
TuF3i
一只区,什么也不想写
分类
标签
站点统计
文章
5
分类
4
标签
8
总字数
9,842
运行时长
0
最后活动
0 天前

目录