Shell 输入/输出重定向
《Shell 输入/输出重定向》深度学习版 🧠
🎉 欢迎来到 Shell 编程中非常关键的一章 —— 输入/输出重定向(I/O Redirection)。掌握它,你将能够完全控制命令的输入来源和输出目的地,实现日志记录、批量处理、错误隔离、自动化任务等高级功能!
🎯 学习目标
- 理解标准输入(stdin)、标准输出(stdout)、标准错误(stderr)的基本概念
- 掌握常见的输入/输出重定向操作符(
>,>>,<,2>,&>,|,tee等) - 能在实际脚本中灵活使用重定向进行日志记录、错误处理、管道组合等操作
- 学会结合
grep,awk,sed,tail等工具提升数据处理能力 - 避免常见陷阱和语法错误,写出健壮可靠的 Shell I/O 控制语句
⭐ 核心重点(知识点速览)
| 类型 | 内容 | 描述 |
|---|---|---|
| 文件描述符 | stdin(0), stdout(1), stderr(2) | 所有 I/O 的基础 |
| 输出重定向 | >、>> |
覆盖或追加写入文件 |
| 错误重定向 | 2>、2>> |
单独处理错误信息 |
| 合并重定向 | &>、1>&2 |
同时控制多个输出流 |
| 输入重定向 | <、<<、<<< |
改变命令输入来源 |
| 管道机制 | `cmd1 | cmd2` |
| 常用工具 | tee, cat, logger |
辅助调试与日志记录 |
📖 详细讲解
一、基本概念:三个标准流 🔄
所有 Shell 命令都默认拥有以下三个“标准流”:
| 文件描述符 | 名称 | 默认行为 |
|---|---|---|
| 0 | stdin | 从键盘读取输入 |
| 1 | stdout | 输出到终端屏幕 |
| 2 | stderr | 错误信息也输出到终端 |
✅ 示例:查看当前进程的标准文件描述符
ls -l /proc/$$/fd
你会看到类似:
0 -> /dev/pts/0
1 -> /dev/pts/0
2 -> /dev/pts/0
二、输出重定向 > 和 >> 📤
>:覆盖写入文件>>:追加写入文件
✅ 示例:将 ls 输出保存到文件
ls > file_list.txt # 覆盖
ls >> file_list.txt # 追加
三、错误重定向 2> 和 2>> 🔴
单独捕获错误信息,不干扰正常输出。
✅ 示例:只记录错误信息
grep "error" /var/log/syslog 2> error.log
四、合并标准输出和标准错误 🟢🔴
&>:同时重定向 stdout 和 stderr(覆盖)&>>:同时重定向 stdout 和 stderr(追加)
✅ 示例:完整记录脚本执行过程
./my_script.sh &> script_output.log
五、输入重定向 <、<<、<<< 📥
<:从文件读取输入<<:Here Document,从脚本中读取多行文本<<<:Here String,传递单个字符串作为输入
✅ 示例:使用 Here Document 创建配置文件
cat << EOF > config.conf
[app]
name = MyApp
version = 1.0
EOF
生成的 config.conf 内容如下:
[app]
name = MyApp
version = 1.0
六、管道 |:连接命令 🔗
将前一个命令的输出作为后一个命令的输入。
✅ 示例:统计 /etc/passwd 中用户数量
cat /etc/passwd | wc -l
或者更简洁写法:
wc -l < /etc/passwd
七、tee 命令:双重输出 🪞
将输出既显示在屏幕上,又保存到文件中。
✅ 示例:实时监控并记录日志
ping google.com | tee ping_log.txt
八、实战案例分析 🧪
🎯 场景一:自动备份日志并清空旧内容 📄
cp /var/log/app.log /backup/app_$(date +%Y%m%d).log && > /var/log/app.log
解释:
cp ... &&:备份完成后> app.log:清空原日志文件内容(零字节)
🎯 场景二:分离标准输出和标准错误 📊
./run_app.sh > output.log 2> error.log
这样可以分别查看程序输出和错误信息。
🎯 场景三:模拟登录验证并记录日志 🛡️
valid_user="admin"
valid_pass="password"
read -p "用户名:" user
read -sp "密码:" pass
if [ "$user" = "$valid_user" ] && [ "$pass" = "$valid_pass" ]; then
echo "$(date): 用户 $user 登录成功" >> auth.log
echo "✅ 登录成功"
else
echo "$(date): 用户 $user 登录失败" >> auth.log
echo "❌ 登录失败"
fi
🎯 场景四:批量执行命令并记录结果 📤
#!/bin/bash
input_file="commands.txt"
output_file="results.log"
while read -r cmd; do
echo "执行命令: $cmd" >> "$output_file"
eval "$cmd" >> "$output_file" 2>&1
done < "$input_file"
commands.txt 内容示例:
ls -la
df -h
uptime
九、不同系统的差异与注意事项 ⚠️
| 项目 | Bash | Dash (Ubuntu 默认) | zsh |
|---|---|---|---|
支持 > |
✅ | ✅ | ✅ |
支持 2> |
✅ | ✅ | ✅ |
支持 &> |
✅ | ✅(dash 可能需升级) | ✅ |
支持 << |
✅ | ✅ | ✅ |
支持 <<< |
✅ | ✅ | ✅ |
| 推荐脚本开头 | #!/bin/bash |
#!/bin/sh |
#!/bin/zsh |
| 注意子 shell 变量作用域 | 是 | 是 | 是 |
📝 小贴士:
- 在 Ubuntu 中默认
/bin/sh是dash,虽然支持大多数重定向,但建议使用bash。 - 使用双引号包裹变量,防止路径含空格出错。
- 重定向顺序很重要,例如
> file 2>&1表示将 stderr 也重定向到 stdout。 >会覆盖文件,使用>>更安全。
⚠️ 常见陷阱 & 解决方案
| 问题 | 原因 | 解决方法 |
|---|---|---|
command not found |
路径未正确设置 | 使用绝对路径或 which 查看 |
Permission denied |
文件权限不足 | 使用 chmod 或 sudo |
ambiguous redirect |
文件名含有空格 | 使用双引号包裹变量 |
No such file or directory |
文件不存在且无法创建 | 检查目录权限或路径拼写 |
Bad file descriptor |
文件描述符编号错误 | 检查是否使用了非法编号如 3> |
🧠 总结与小贴士
| 技巧 | 说明 |
|---|---|
> 是 Shell 的“输出控制器” |
让你能自由指定输出去向 |
2> 是“错误处理器” |
专门处理错误信息,便于调试 |
| ` | ` 是“数据管道” |
tee 是“双面镜” |
显示输出的同时保存日志 |
<< 是“内嵌文档” |
适合写模板、配置片段 |
推荐统一使用 bash 编写脚本 |
功能更强,兼容性更好 |
| 使用双引号包裹变量 | 防止空格或特殊字符出错 |
📚 推荐练习题(可选)
- 编写一个脚本,将系统当前时间、负载信息写入日志文件,并保留最近 5 条记录。
- 写一个脚本,循环执行
ping,并将失败的信息记录到日志中。 - 实现一个函数
log(),接收等级和消息参数,自动添加时间戳并写入日志文件。 - 编写一个脚本,将
top命令运行 10 秒后自动退出,并将结果保存到文件。 - 创建一个菜单脚本,每次选择都会记录到日志文件中,并附带时间戳。

浙公网安备 33010602011771号