管道与过滤器
什么是管道?
管道(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 -Runiq - 去重
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 -icut - 剪切列
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-10paste - 合并列
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 5wc - 统计
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 -Ltee - 分流
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 -lxargs - 构建参数
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 高效操作的关键。
上一章:输入输出重定向
下一章:文本编辑器