Linux: 标准流与重定向——stdin / stdout / stderr

Linux 把每个程序都看作一个"过滤器"——从某处接收输入、处理后输出结果。输入和输出的通道就是标准流

📋 前置知识:需要先掌握以下内容

1. 你将学到


2. 一个满屏报错的故事

(1) 痛点:命令输出混在一起,找不到想要的信息

小明运行 apt update,成功的信息和红色的错误信息混在一起满屏滚动。他只想把成功的结果存起来,把错误单独看。

(2) 用重定向分开输出

Bob 教他用重定向:

BASH
# 成功信息存到 success.log,错误信息存到 error.log
sudo apt update > success.log 2> error.log

# 查看错误
cat error.log

(3) 收益:精准控制输出

小明学会了将不同输出分流——日志文件只记录成功的,终端只显示重要的,错误单独保存方便排查。


3. 知识点讲解

(1) 三大标准流

Linux 程序启动时自动获得三个文件描述符:

文件描述符 名称 默认连接 用途
0 stdin 键盘 程序的输入
1 stdout 终端屏幕 程序的正常输出
2 stderr 终端屏幕 程序的错误输出
TEXT 📖 仅展示

         ┌──────────┐
stdin ──→│          │──→ stdout
(键盘)   │  程序    │    (屏幕)
         │          │──→ stderr
         └──────────┘    (屏幕)

(2) 重定向操作符

操作符 含义 示例
> 将 stdout 写入文件(覆盖) ls > files.txt
>> 将 stdout 追加到文件 echo "done" >> log.txt
< 从文件读取 stdin sort < list.txt
2> 将 stderr 写入文件 cmd 2> error.log
2>> 追加 stderr 到文件 cmd 2>> error.log
&> 将 stdout 和 stderr 都写入文件 cmd &> all.log
&>> 追加 stdout 和 stderr 到文件 cmd &>> all.log
2>&1 将 stderr 合并到 stdout cmd > log.txt 2>&1

ℹ️ 说明> 是覆盖写入(文件原有内容会被清空),>> 是追加写入(在文件末尾添加)。需要保存历史日志时务必用 >>;需要干净的状态时用 >。误用 > 会覆盖重要日志文件。

(3) /dev/null——黑魔法

/dev/null 是一个特殊的设备文件——写入它的任何数据都会被丢弃,读取它会返回空。

💡 提示/dev/null 是 Linux 的"黑洞设备"——内核在驱动层面直接丢弃写入的数据,不占用磁盘空间,永远不会满。常用于静默命令输出:command &> /dev/null 完全不显示任何输出,command 2> /dev/null 只屏蔽错误。

TEXT 📖 仅展示
# 忽略所有输出
command > /dev/null 2>&1

# 或者更简洁的写法
command &> /dev/null

# 只忽略错误
command 2> /dev/null

# 只忽略正常输出
command > /dev/null

▶ 示例:保存命令输出到文件

BASH
# 覆盖写入
ls ~ > home-directory.txt
cat home-directory.txt

# 追加写入
echo "新的一行" >> home-directory.txt
echo "又来一行" >> home-directory.txt
cat home-directory.txt

输出:

TEXT 📖 仅展示
Desktop
Documents
Downloads

新的一行 又来一行

▶ 示例:分离正常输出和错误输出

BASH
# 成功信息保存,错误信息单独看
find /etc -name "*.conf" > found.txt 2> errors.txt

# 查看结果
echo "=== 找到的配置文件 ==="
head -5 found.txt

echo "=== 错误信息 ==="
cat errors.txt

输出:

TEXT 📖 仅展示
=== 找到的配置文件 ===
/etc/adduser.conf
/etc/ca-certificates.conf
/etc/debconf.conf
/etc/deluser.conf
/etc/fuse.conf
=== 错误信息 ===
find: '/etc/ssl/private': Permission denied

▶ 示例:合并输出

BASH
# 方式一:&>(bash 4+)
grep -r "error" /var/log/ &> all-results.txt

# 方式二:2>&1(更通用)
grep -r "error" /var/log/ > all-results.txt 2>&1

# 两种方式效果一样——stdout 和 stderr 都存入同一个文件

> 💡 **提示**:`2>&1` 的顺序很重要!`cmd > log.txt 2>&1` 是正确的——先将 stdout 重定向到文件,再把 stderr 合并到 stdout(此时 stdout 已经指向文件)。如果写成 `cmd 2>&1 > log.txt`,stderr 会先合并到屏幕上的 stdout,然后 stdout 才重定向到文件,stderr 仍然输出到屏幕。

输出:

TEXT 📖 仅展示
$ wc -l all-results.txt
42 all-results.txt

▶ 示例:/dev/null 屏蔽输出

BASH
# 完全静默运行
sudo apt update > /dev/null 2>&1

# 简洁写法
sudo apt update &> /dev/null

# 只屏蔽错误
find / -name "*.py" 2> /dev/null

输出:

TEXT 📖 仅展示
(无输出——所有错误和正常结果均被屏蔽)

▶ 示例:heredoc——在脚本中嵌入多行文本

BASH
# 创建多行配置文件
cat << EOF > nginx.conf
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
}
EOF

# 追加多行文本
cat << EOF >> ~/.bashrc
# 添加 PATH
export PATH="\$PATH:\$HOME/scripts"
EOF

# heredoc 中的变量不会被展开(用 'EOF' 加引号)
cat << 'EOF' > greeting.sh
#!/bin/bash
echo "Hello, $USER"    # $USER 保留为变量名
EOF

输出:

TEXT 📖 仅展示
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
}

▶ 综合示例:编译程序时的输出管理

BASH
# 编译 C 程序,分别记录输出和错误
gcc main.c -o app \
    > build.log \        # 编译成功信息
    2> build-errors.log  # 编译错误信息

# 如果编译成功,build-errors.log 是空的
# 如果编译失败,查看错误
if [ -s build-errors.log ]; then
    echo "❌ 编译失败,错误信息:"
    cat build-errors.log
else
    echo "✅ 编译成功!"
fi

❓ 常见问题

Q: >|(管道)有什么区别? A: \1

Q: 2>&1 是什么意思? A: \1

Q: 为什么用 &> 不用 2>&1A: &> 是 bash 4+ 的语法糖,更简洁。2>&1 更通用(在 sh 中也能用)。两者功能相同。

Q: /dev/null 是真空吗?会满吗? A: 不会。写入 /dev/null 的数据被内核直接丢弃,不占用任何磁盘空间。可以说是"无限容量的黑洞"。

Q: heredoc 里的 EOF 必须大写吗? A: 不必须。EOF 只是惯例,可以用任何字符串(EOLEND__EOF__)。关键是开始和结束的标记必须完全一致。


📖 小节


📝 作业

  1. 基础题(难度⭐):用 ls -la 将输出保存到 home-list.txt,然后用 >> 追加当前日期
  2. 进阶题(难度⭐⭐):运行 find / -name "*.py" 2> errors.txt 查看权限拒绝错误,然后用 &> 同时捕获 stdout 和 stderr 到同一个文件,用 /dev/null 屏蔽错误输出
  3. 挑战题(难度⭐⭐⭐):用 heredoc 创建一个包含 5 行内容的配置文件,然后写一个脚本分别用 >2>&>>> 演示四种重定向方式,并解释每种场景的适用情况
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏