管道与重定向 #
标准流 #
三种标准流 #
text
┌─────────────────────────────────────────────────────────────┐
│ 标准流 │
├─────────────────────────────────────────────────────────────┤
│ │
│ stdin (0) 标准输入 │
│ stdout (1) 标准输出 │
│ stderr (2) 标准错误 │
│ │
│ 默认: │
│ stdin -> 键盘 │
│ stdout -> 终端 │
│ stderr -> 终端 │
│ │
└─────────────────────────────────────────────────────────────┘
输出重定向 #
基本重定向 #
bash
# 重定向输出到文件(覆盖)
$ echo "Hello" > file.txt
# 重定向输出到文件(追加)
$ echo "World" >> file.txt
# 重定向标准输出
$ ls -la > output.txt
$ ls -la 1> output.txt
# 重定向标准错误
$ ls /nonexistent 2> error.txt
# 重定向标准输出和标准错误
$ ls -la > all.txt 2>&1
$ ls -la &> all.txt
$ ls -la >& all.txt
# 追加标准输出和标准错误
$ ls -la >> all.txt 2>&1
# 丢弃输出
$ ls -la > /dev/null
$ ls -la 2> /dev/null
$ ls -la &> /dev/null
重定向到不同文件 #
bash
# 标准输出和标准错误分别重定向
$ command > output.txt 2> error.txt
# 标准输出追加,标准错误覆盖
$ command >> output.txt 2> error.txt
# 标准输出丢弃,保存错误
$ command > /dev/null 2> error.txt
输入重定向 #
基本输入重定向 #
bash
# 从文件读取输入
$ wc -l < file.txt
# 从文件读取并处理
$ sort < unsorted.txt > sorted.txt
# 从文件读取多行
$ cat << EOF
line 1
line 2
line 3
EOF
Here Document #
bash
# Here Document
$ cat << EOF
This is line 1
This is line 2
This is line 3
EOF
# 禁止变量展开
$ cat << 'EOF'
$HOME is not expanded
EOF
# 去除前导制表符
$ cat <<- EOF
This line has leading tabs removed
EOF
# 使用变量
$ name="World"
$ cat << EOF
Hello, $name!
EOF
# 在脚本中使用
#!/bin/bash
cat << EOF > config.ini
[database]
host = localhost
port = 3306
EOF
Here String #
bash
# Here String(单行)
$ cat <<< "Hello World"
# 使用变量
$ name="John"
$ cat <<< "Hello, $name"
# 传递给命令
$ bc <<< "2 + 2"
4
$ awk '{print $1}' <<< "Hello World"
Hello
管道 #
基本管道 #
bash
# 管道将一个命令的输出作为另一个命令的输入
$ ls -la | grep ".txt"
$ cat file.txt | sort | uniq
# 多级管道
$ cat access.log | grep "ERROR" | awk '{print $1}' | sort | uniq -c
# 管道与重定向组合
$ ls -la | grep ".txt" > txt_files.txt
管道与 tee #
bash
# tee 同时输出到文件和屏幕
$ ls -la | tee output.txt
# 追加模式
$ ls -la | tee -a output.txt
# 多个文件
$ ls -la | tee file1.txt file2.txt
# 管道中间使用 tee
$ cat file.txt | tee copy.txt | grep "pattern"
# 同时保存标准输出和标准错误
$ command 2>&1 | tee output.txt
管道与错误处理 #
bash
# 管道中的错误处理
# 默认管道返回最后一个命令的状态
# 使用 PIPESTATUS
$ false | true
$ echo ${PIPESTATUS[@]}
1 0
# 检查管道中每个命令的状态
$ command1 | command2 | command3
if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "command1 failed"
fi
# 使用 set -o pipefail
$ set -o pipefail
$ false | true
$ echo $?
1
进程替换 #
进程替换语法 #
bash
# 进程替换
# <(command) 输出作为文件
# >(command) 输入作为文件
# 比较两个命令的输出
$ diff <(ls dir1) <(ls dir2)
# 合并输出
$ cat <(echo "first") <(echo "second")
# 发送输出到多个进程
$ echo "Hello" | tee >(grep -o "H" > h.txt) >(grep -o "e" > e.txt)
# 使用进程替换作为输入
$ sort <(cat file1.txt) <(cat file2.txt)
实用示例 #
bash
# 比较两个目录
$ diff -r <(ls -R dir1) <(ls -R dir2)
# 合并排序两个文件
$ sort -m <(sort file1.txt) <(sort file2.txt)
# 查找两个文件的差异
$ comm <(sort file1.txt) <(sort file2.txt)
# 使用多个输入
$ paste <(cut -f1 file.txt) <(cut -f3 file.txt)
# 日志分析
$ grep "ERROR" <(cat log1.txt) <(cat log2.txt)
文件描述符 #
自定义文件描述符 #
bash
# 打开文件描述符
$ exec 3> output.txt # 打开文件描述符 3 用于写入
# 写入文件描述符
$ echo "Hello" >&3
# 读取文件描述符
$ exec 4< input.txt # 打开文件描述符 4 用于读取
$ read line <&4
# 关闭文件描述符
$ exec 3>&- # 关闭写入
$ exec 4<&- # 关闭读取
# 读写模式
$ exec 3<> file.txt # 打开文件描述符 3 用于读写
# 复制文件描述符
$ exec 4>&1 # 将 stdout 复制到 4
$ exec 1> output.txt # 重定向 stdout
$ echo "To file"
$ exec 1>&4 # 恢复 stdout
$ echo "To terminal"
实用示例 #
bash
#!/bin/bash
# 同时写入多个文件
exec 3> output1.txt
exec 4> output2.txt
echo "Line 1" | tee >&3 >&4
echo "Line 2" | tee >&3 >&4
exec 3>&-
exec 4>&-
# 日志记录
exec 3> >(tee -a log.txt)
echo "Log message" >&3
exec 3>&-
重定向技巧 #
重定向顺序 #
bash
# 重定向顺序很重要
# 正确:先重定向 stdout,再重定向 stderr
$ command > file.txt 2>&1
# 错误:stderr 仍然输出到终端
$ command 2>&1 > file.txt
# 解释:
# 2>&1 将 stderr 重定向到 stdout 当前指向的位置
# 在第一个例子中,stdout 已经重定向到 file.txt
# 在第二个例子中,stdout 还指向终端
常见模式 #
bash
# 静默模式(丢弃所有输出)
$ command &> /dev/null
# 只保存错误
$ command > /dev/null 2> error.txt
# 保存所有输出
$ command &> output.txt
# 分别保存
$ command > output.txt 2> error.txt
# 同时显示和保存
$ command 2>&1 | tee output.txt
# 追加模式
$ command >> output.txt 2>> error.txt
调试重定向 #
bash
# 查看文件描述符
$ ls -la /proc/$$/fd/
# 查看打开的文件
$ lsof -p $$
# 查看重定向状态
$ exec
小结 #
通过本节学习,你应该掌握:
- 标准流:stdin、stdout、stderr
- 输出重定向:>、>>、2>、&>
- 输入重定向:<、<<、<<<
- 管道:|、tee
- 进程替换:<()、>()
- 文件描述符:exec、自定义描述符
下一步,我们将学习高级工具。
最后更新:2026-04-11