Skip to content

管道与过滤器

什么是管道?

管道(Pipe)是 Unix/Linux 最强大的特性之一。它使用 | 符号将一个命令的输出作为另一个命令的输入,从而将多个简单命令组合成复杂的数据处理流程。

┌─────────┐         ┌─────────┐         ┌─────────┐
│ 命令 1   │  stdout │ 命令 2   │  stdout │ 命令 3   │
│         ├────────►│         ├────────►│         │
│         │    |    │         │    |    │         │
└─────────┘         └─────────┘         └─────────┘

基本语法

bash
命令1 | 命令2 | 命令3 | ...

简单示例

bash
# 列出文件并分页显示
$ ls -la | less

# 统计文件数量
$ ls | wc -l

# 查找并计数
$ grep "error" logfile.txt | wc -l

# 多级管道
$ cat file.txt | grep "pattern" | sort | uniq

过滤器命令

过滤器是接收标准输入、处理数据、输出到标准输出的程序。

grep - 文本搜索

bash
# 基本搜索
$ cat file.txt | grep "pattern"

# 不区分大小写
$ cat file.txt | grep -i "pattern"

# 显示行号
$ cat file.txt | grep -n "pattern"

# 反向匹配
$ cat file.txt | grep -v "pattern"

# 统计匹配行数
$ cat file.txt | grep -c "pattern"

# 只显示匹配部分
$ cat file.txt | grep -o "pattern"

# 扩展正则表达式
$ cat file.txt | grep -E "pattern1|pattern2"

# 显示上下文
$ cat file.txt | grep -A 2 -B 2 "pattern"  # 前后各 2 行
$ cat file.txt | grep -C 3 "pattern"        # 前后各 3 行

sort - 排序

bash
# 基本排序(按字母)
$ cat file.txt | sort

# 逆序排序
$ cat file.txt | sort -r

# 数字排序
$ cat file.txt | sort -n

# 按指定列排序
$ cat file.txt | sort -k 2      # 按第 2 列
$ cat file.txt | sort -k 2,2    # 只按第 2 列
$ cat file.txt | sort -k 2 -n   # 第 2 列数字排序

# 按分隔符分列
$ cat file.txt | sort -t ':' -k 3 -n

# 去重排序
$ cat file.txt | sort -u

# 人类可读的大小排序
$ du -h | sort -h

# 随机排序
$ cat file.txt | sort -R

uniq - 去重

bash
# 去除连续重复行(需要先排序)
$ cat file.txt | sort | uniq

# 只显示重复的行
$ cat file.txt | sort | uniq -d

# 只显示不重复的行
$ cat file.txt | sort | uniq -u

# 统计每行出现次数
$ cat file.txt | sort | uniq -c

# 按出现次数排序
$ cat file.txt | sort | uniq -c | sort -rn

# 忽略大小写
$ cat file.txt | sort | uniq -i

cut - 剪切列

bash
# 按字符位置切割
$ echo "Hello World" | cut -c 1-5
Hello

# 按字段切割(默认 Tab 分隔)
$ cat file.txt | cut -f 1,3

# 指定分隔符
$ cat /etc/passwd | cut -d ':' -f 1,3
# 提取用户名和 UID

# 提取范围
$ cat file.txt | cut -d ',' -f 2-4    # 第 2 到 4 列
$ cat file.txt | cut -d ',' -f 3-     # 第 3 列到最后
$ cat file.txt | cut -d ',' -f -3     # 第 1 到 3 列

# 按字节切割
$ cat file.txt | cut -b 1-10

paste - 合并列

bash
# 并排合并文件
$ paste file1.txt file2.txt

# 指定分隔符
$ paste -d ',' file1.txt file2.txt

# 将一个文件的行合并成一行
$ paste -s file.txt

# 每 N 行合并
$ cat file.txt | paste - - -    # 每 3 行合并

tr - 字符转换

bash
# 转换字符
$ echo "hello" | tr 'a-z' 'A-Z'
HELLO

# 删除字符
$ echo "hello 123" | tr -d '0-9'
hello

# 压缩重复字符
$ echo "hello     world" | tr -s ' '
hello world

# 删除换行符
$ cat file.txt | tr -d '\n'

# 替换字符
$ echo "hello:world" | tr ':' ' '
hello world

# 删除非打印字符
$ cat file.txt | tr -cd '[:print:]\n'

# 字符集
# [:alpha:] 字母
# [:digit:] 数字
# [:alnum:] 字母和数字
# [:space:] 空白字符
# [:lower:] 小写字母
# [:upper:] 大写字母

head 和 tail

bash
# 前 10 行
$ cat file.txt | head

# 前 N 行
$ cat file.txt | head -n 5

# 除了最后 N 行
$ cat file.txt | head -n -5

# 后 10 行
$ cat file.txt | tail

# 后 N 行
$ cat file.txt | tail -n 5

# 从第 N 行开始
$ cat file.txt | tail -n +5

# 组合使用(第 5-10 行)
$ cat file.txt | head -n 10 | tail -n 5

wc - 统计

bash
# 统计行数、单词数、字节数
$ cat file.txt | wc
    100     500    3000

# 只统计行数
$ cat file.txt | wc -l

# 只统计单词数
$ cat file.txt | wc -w

# 只统计字符数
$ cat file.txt | wc -m

# 只统计字节数
$ cat file.txt | wc -c

# 最长行的长度
$ cat file.txt | wc -L

tee - 分流

bash
# 同时输出到屏幕和文件
$ ls -la | tee filelist.txt

# 追加模式
$ ls -la | tee -a filelist.txt

# 输出到多个文件
$ ls -la | tee file1.txt file2.txt file3.txt

# 在管道中间保存
$ cat file.txt | grep "error" | tee errors.txt | wc -l

xargs - 构建参数

bash
# 将输入转换为命令参数
$ echo "file1 file2 file3" | xargs rm

# 每次一个参数
$ cat files.txt | xargs -n 1 rm

# 指定替换位置
$ find . -name "*.txt" | xargs -I {} cp {} /backup/

# 并行执行
$ cat urls.txt | xargs -n 1 -P 4 wget

# 处理含空格的文件名
$ find . -name "*.txt" -print0 | xargs -0 rm

# 交互确认
$ find . -name "*.tmp" | xargs -p rm

# 显示执行的命令
$ echo "a b c" | xargs -t echo
echo a b c
a b c

实用管道组合

文件分析

bash
# 统计文件类型
$ find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn

# 查找最大的 10 个文件
$ find . -type f -exec du -h {} + | sort -rh | head -10

# 统计代码行数
$ find . -name "*.py" | xargs wc -l | tail -1

# 查找重复文件(按大小)
$ find . -type f -exec du -b {} + | sort -n | uniq -d -w 10

日志分析

bash
# 统计 IP 访问次数
$ cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

# 查找错误日志
$ cat app.log | grep -i "error" | tail -20

# 按时间过滤
$ cat app.log | grep "2025-01-09" | grep "ERROR"

# 统计 HTTP 状态码
$ cat access.log | awk '{print $9}' | sort | uniq -c | sort -rn

# 实时监控错误
$ tail -f app.log | grep --line-buffered "ERROR"

文本处理

bash
# 提取 email 地址
$ grep -E -o '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' file.txt

# 提取 URL
$ grep -E -o 'https?://[^ ]+' file.txt

# 统计单词频率
$ cat file.txt | tr -s ' ' '\n' | tr '[:upper:]' '[:lower:]' | sort | uniq -c | sort -rn

# 删除空行
$ cat file.txt | grep -v '^$'

# 删除注释行
$ cat config.txt | grep -v '^#'

系统管理

bash
# 查看最占 CPU 的进程
$ ps aux | sort -k 3 -rn | head -10

# 查看最占内存的进程
$ ps aux | sort -k 4 -rn | head -10

# 查看登录用户
$ who | cut -d ' ' -f 1 | sort | uniq

# 查看监听端口
$ ss -tlnp | grep LISTEN

# 查找大目录
$ du -h --max-depth=1 | sort -rh | head -10

数据转换

bash
# CSV 转 TSV
$ cat file.csv | tr ',' '\t'

# JSON 字段提取(需要 jq)
$ cat data.json | jq '.name'

# 列转行
$ cat file.txt | paste -s -d ','

# 行转列
$ cat file.txt | tr ',' '\n'

管道与重定向组合

bash
# 保存输出和错误到不同文件
$ command 2>&1 | tee output.txt

# 管道错误输出
$ command 2>&1 | grep "error"

# 使用进程替换
$ diff <(sort file1.txt) <(sort file2.txt)

# 同时处理多个输入
$ cat file1.txt file2.txt | sort | uniq

管道的注意事项

管道缓冲

bash
# 使用 stdbuf 控制缓冲
$ tail -f log.txt | stdbuf -oL grep "pattern"

# grep 的 --line-buffered 选项
$ tail -f log.txt | grep --line-buffered "pattern"

管道与子 Shell

bash
# 管道会创建子 Shell,变量不会传递到父 Shell
$ count=0
$ cat file.txt | while read line; do
    ((count++))
done
$ echo $count  # 0,不是预期结果

# 解决方法 1:使用进程替换
$ count=0
$ while read line; do
    ((count++))
done < <(cat file.txt)
$ echo $count

# 解决方法 2:使用 lastpipe
$ shopt -s lastpipe
$ count=0
$ cat file.txt | while read line; do
    ((count++))
done
$ echo $count

获取管道状态

bash
# $? 只返回最后一个命令的状态
$ false | true
$ echo $?  # 0

# 使用 PIPESTATUS 数组(Bash)
$ false | true
$ echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}  # 1 0

# 使用 pipefail 选项
$ set -o pipefail
$ false | true
$ echo $?  # 1

小结

本章介绍了 Linux 管道和过滤器:

  • 管道 |:连接命令,构建数据处理流程
  • grep:文本搜索
  • sort/uniq:排序和去重
  • cut/paste:列操作
  • tr:字符转换
  • head/tail:查看文件头尾
  • wc:统计
  • tee:分流输出
  • xargs:构建命令参数

Unix 哲学提倡"做一件事并做好",管道让我们能够组合这些简单的工具完成复杂的任务。熟练使用管道是 Linux 高效操作的关键。


上一章:输入输出重定向

下一章:文本编辑器