第9章:管道与重定向

第九章:管道与重定向

9.1 什么是管道(|)?管道的作用

管道(Pipe)是 Linux 最强大的特性之一!它用 | 符号连接两个命令,让前一个命令的输出成为后一个命令的输入

想象一下:你有一台果汁机,第一台机器把水果榨成汁,第二台机器把果汁过滤。管道就是这个连接两台机器的管子!

🍔 更接地气的比喻:想象你在快餐店点汉堡:

  • cat 是取餐员,把原材料(文件内容)拿出来
  • grep 是质检员,筛选出符合条件的(比如"牛肉汉堡")
  • sort 是排序员,按价格排好序
  • head 是打包员,只拿前3个
  • 管道 | 就是传送带,把东西从一个工序传到下一个工序

没有传送带?那你得手动搬,累死人!有了管道,每个程序专注于自己的活,配合起来效率爆表!

9.1.1 管道连接命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 语法
命令1 | 命令2 | 命令3

# 示例:查看当前用户 processes,并只显示前10行
ps aux | head -n 10

# 解释:
# ps aux → 列出所有进程
# | → 把进程列表传给下一个命令
# head -n 10 → 只显示前10行

ps aux 会列出超多进程,你根本看不完。用管道接 head,就只看前几条了!

9.1.2 管道的工作原理

graph LR
    A["命令1"] --> B["标准输出 stdout"]
    B --> C["管道 |"]
    C --> D["命令2 的输入"]
    D --> E["命令2"]
    E --> F["最终输出"]
    
    subgraph 管道连接示意
        B
        C
        D
    end

专业术语:标准输出(stdout)是命令默认输出到屏幕的数据流。管道把这个数据流"重定向"到下一个命令的标准输入(stdin)。

9.1.3 管道实战

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 实战例子:

# 1. 查找进程,排除 grep 自身
ps aux | grep python | grep -v grep

# 2. 统计当前目录文件数量
ls -l | wc -l

# 3. 查看内存使用情况,按使用量排序
free -h | sort -rh | head -n 5

# 4. 查看日志最新10行,搜索 error
tail -f /var/log/syslog | grep error

# 5. 统计命令输出中有多少个"error"
dmesg | grep -i error | wc -l

管道是 Unix 哲学的体现:一个程序只做一件事,但做好它。多个简单程序通过管道组合,就能完成复杂任务!


9.2 输出重定向:> 和 »

重定向让你可以把命令的输出保存到文件,而不是显示在屏幕上。

9.2.1 命令 > 文件:覆盖写入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 把命令输出写入文件(覆盖原有内容)
echo "Hello, World!" > greeting.txt

# 查看文件内容
cat greeting.txt
# Hello, World!

# 再次写入,会覆盖!
echo "Goodbye!" > greeting.txt
cat greeting.txt
# Goodbye!  (之前的内容没了)

9.2.2 命令 » 文件:追加写入

1
2
3
4
5
6
7
8
9
# 追加内容到文件末尾(不覆盖原有内容)
echo "First line" >> file.txt
echo "Second line" >> file.txt
echo "Third line" >> file.txt

cat file.txt
# First line
# Second line
# Third line
graph LR
    A["echo Hello > a.txt"] --> B["a.txt 内容: Hello"]
    A --> C["覆盖"]
    
    D["echo World >> a.txt"] --> E["a.txt 内容: Hello"]
    E --> F["World"]
    F --> G["追加"]

小技巧:可以用 > /dev/null 丢弃输出,不显示也不保存:

1
2
command > /dev/null 2>&1
# /dev/null 是一个特殊的"黑洞"设备,写进去的东西全消失

9.3 错误重定向:2> 和 2»

命令输出有两类:标准输出(stdout,正常输出)和标准错误输出(stderr,错误信息)。

9.3.1 将错误输出重定向到文件

1
2
3
4
5
6
# 2> 把 stderr 重定向到文件
ls /nonexistent 2> errors.txt

# 查看错误信息
cat errors.txt
# ls: cannot access '/nonexistent': No such file or directory

数字含义:

  • 0 = 标准输入(stdin)
  • 1 = 标准输出(stdout)
  • 2 = 标准错误输出(stderr)

9.3.2 追加错误输出

1
2
3
4
5
6
7
# 2>> 追加错误到文件(不覆盖)
ls /nonexistent 2>> errors.txt
ls /another_missing 2>> errors.txt

cat errors.txt
# ls: cannot access '/nonexistent': No such file or directory
# ls: cannot access '/another_missing': No such file or directory

9.4 正确输出和错误输出重定向:&>

有时候你希望把正常输出和错误输出都重定向到一个地方

9.4.1 &> 重定向所有输出

1
2
3
4
5
# &> 同时重定向 stdout 和 stderr(bash 特性,非 POSIX 标准)
command &> all_output.txt

# 更通用的写法(兼容所有 shell):
command > all_output.txt 2>&1

⚠️ 兼容性注意&>bash 的语法糖,在 dashsh 等传统 shell 中不支持。写脚本时建议用 > file 2>&1 这种通用写法,兼容性更好!

9.4.2 &» 追加所有输出

1
2
# &>> 追加方式重定向所有输出
command &>> log.txt

9.4.3 常见用法

1
2
3
4
5
6
7
8
# 把所有输出重定向到 /dev/null(丢弃一切)
command > /dev/null 2>&1

# 把错误重定向到标准输出,然后一起重定向
ls /home /nonexistent > output.txt 2>&1

# 查看哪些命令执行失败(查看 stderr)
make 2> errors.log

9.5 输入重定向:< 和 «

输入重定向让命令从文件字符串读取输入,而不是从键盘。

9.5.1 命令 < 文件

1
2
3
4
5
6
# 让 wc 从文件读取输入(而不是从键盘)
wc < file.txt

# 等价于:
wc file.txt
# (但 < 重定向更明确地表示"从文件读取")

9.5.2 命令 « EOF

<< 叫做 Here Document,允许你在命令中直接输入多行文本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 用 cat 创建一个文件(here document 方式)
cat > notes.txt << EOF
这是一个多行文本
第二行内容
第三行内容
今天是 2024年1月15日
EOF

# cat 会把 << 和 EOF 之间所有内容作为输入
# EOF 只是自定义的分隔符,可以换成其他词

Here Document 非常适合在脚本中嵌入多行文本!

9.5.3 Here String

1
2
3
4
5
# <<< 是 Here String,只输入一行字符串
wc <<< "hello world"

# 等价于:
echo "hello world" | wc

9.6 xargs 命令:将输出转为命令行参数

xargs管道传来的数据转换成命令行参数传递给其他命令。

9.6.1 基本用法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# ⚠️ 危险用法:文件名有空格会出错!
find . -name "*.log" | xargs rm

# ✅ 更安全的用法(处理特殊字符):
find . -name "*.log" -exec rm {} \;
# 或者
find . -name "*.log" -print0 | xargs -0 rm

# 解释:
# find 找到所有 .log 文件
# -exec rm {} \; 逐个删除,能正确处理空格
# 或者 -print0 | xargs -0 也能安全处理空格

🚨 安全性对比

  • find | xargs rm:**危险!**文件名有空格会出错
  • find -exec rm {} \;安全,能正确处理空格和特殊字符
  • find -print0 | xargs -0 rm安全,推荐用于大量文件

9.6.2 find . -name “*.log” | xargs rm

1
2
3
4
5
6
7
8
9
# 完整示例:
# 1. 先看看找到哪些文件(不删除)
find . -name "*.log"

# 2. 确认无误后,删除
find . -name "*.log" | xargs rm

# 3. 如果文件名有空格,加 -print0 和 xargs -0
find . -name "*.log" -print0 | xargs -0 rm

9.6.3 xargs 的其他选项

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# -n 指定每次传递几个参数
find . -name "*.txt" | xargs -n 1 mv -t ./backup/
# 每次传1个参数,逐个移动到 backup 目录

# -I 指定占位符
find . -name "*.txt" | xargs -I {} mv {} ./backup/
# {} 是占位符,代表找到的文件名

# -p 显示将要执行的命令(interactive)
find . -name "*.txt" | xargs -p rm
# 执行前会询问:rm file1.txt file2.txt ...? y/n
graph TD
    A["find 命令"] --> B["找到所有 .log 文件"]
    B --> C["管道 |"]
    C --> D["xargs"]
    D --> E["转换为 rm 参数"]
    E --> F["删除文件"]

9.7 tee 命令:同时输出到文件和屏幕

tee 名字来自英语的"T形管道"——就像水管的三通,一边进,两边出!

9.7.1 命令 | tee 文件

1
2
3
4
5
# tee 读取 stdin,写入文件和屏幕
echo "Hello, tee!" | tee output.txt

# 输出到屏幕:Hello, tee!
# 同时保存到 output.txt

9.7.2 tee -a 追加

1
2
3
4
5
6
7
# -a = append,追加模式
echo "First" | tee file.txt
echo "Second" | tee -a file.txt

cat file.txt
# First
# Second

9.7.3 tee 的实际应用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 场景1:安装软件时同时记录日志
sudo apt install nginx | tee install_log.txt

# 场景2:管道链中使用 tee
echo "Starting process" | tee -a log.txt && \
    long_running_command | tee -a log.txt && \
    echo "Process completed" | tee -a log.txt

# 场景3:tee 到多个文件
echo "data" | tee file1.txt file2.txt file3.txt

tee 和重定向的区别:

  • command > file.txt → 只保存到文件,屏幕看不到
  • command | tee file.txt → 既保存到文件,又显示到屏幕

9.8 实战:管道组合命令分析日志

让我们来一个综合实战,用管道组合命令分析日志!

9.8.1 统计错误数量

1
2
3
4
5
# 统计日志中 error 的数量
grep -i "error" /var/log/syslog | wc -l

# 如果有多个日志文件:
cat /var/log/*.log | grep -i error | wc -l

9.8.2 实时监控错误

1
2
3
4
5
# 实时显示最新的 error 日志
tail -f /var/log/syslog | grep -i error

# 或者只显示最近的50条错误
tail -n 100 /var/log/syslog | grep -i error

9.8.3 统计访问量最高的 IP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 分析 nginx 访问日志,统计 IP 访问量
cat /var/log/nginx/access.log | \
    awk '{print $1}' | \
    sort | \
    uniq -c | \
    sort -rn | \
    head -n 10

# 解释:
# awk '{print $1}' → 提取第一列(IP)
# sort → 排序
# uniq -c → 去重并统计数量
# sort -rn → 按数量倒序排序
# head -n 10 → 只显示前10

9.8.4 分析网站流量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 统计最常用的请求路径
cat /var/log/nginx/access.log | \
    awk '{print $7}' | \
    sort | \
    uniq -c | \
    sort -rn | \
    head -n 10

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

9.8.5 清理旧日志

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# ⚠️ 危险写法:文件名有空格会出错!
find /var/log -name "*.log" -mtime +7 | xargs rm

# ✅ 安全写法1:使用 -delete(推荐)
find /var/log -name "*.log" -mtime +7 -delete

# ✅ 安全写法2:使用 -exec
find /var/log -name "*.log" -mtime +7 -exec rm {} \;

# ✅ 安全写法3:使用 -print0 | xargs -0
find /var/log -name "*.log" -mtime +7 -print0 | xargs -0 rm

# 先确认要删除哪些文件(不删除,只显示)
find /var/log -name "*.log" -mtime +7 -ls
graph LR
    A["日志分析流程"] --> B["cat 读取日志"]
    B --> C["grep 过滤"]
    C --> D["awk 提取字段"]
    D --> E["sort 排序"]
    E --> F["uniq 去重统计"]
    F --> G["head 取前N条"]

本章小结

本章我们学习了 Linux 中的管道与重定向!

管道(|)总结:

1
2
# 管道把前一个命令的输出传给后一个命令
命令1 | 命令2 | 命令3

输出重定向总结:

符号作用
>覆盖重定向 stdout
>>追加重定向 stdout
2>重定向 stderr
2>>追加重定向 stderr
&>重定向所有输出
&>>追加重定向所有输出

输入重定向总结:

符号作用
<从文件读取输入
<< EOFHere Document,多行输入
<<<Here String,单行输入

xargs 和 tee:

命令作用
xargs把输出转成命令行参数
tee同时输出到文件和屏幕

常用管道组合:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 统计
ls | wc -l              # 统计文件数
grep -c "error" log.txt # 统计匹配行数

# 过滤
ps aux | grep python    # 查找进程
history | grep apt      # 查找历史命令

# 分析
cat log | awk '{print $1}' | sort | uniq -c | sort -rn | head

重定向到 /dev/null:

1
command > /dev/null 2>&1  # 丢弃所有输出

下一章我们将学习压缩与归档,掌握 targzipzip 等工具!敬请期待!

最后修改 March 24, 2026: 新增JavaScript教程 (37305c4)