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/shdash,虽然支持大多数重定向,但建议使用 bash
  • 使用双引号包裹变量,防止路径含空格出错。
  • 重定向顺序很重要,例如 > file 2>&1 表示将 stderr 也重定向到 stdout。
  • > 会覆盖文件,使用 >> 更安全。

⚠️ 常见陷阱 & 解决方案

问题 原因 解决方法
command not found 路径未正确设置 使用绝对路径或 which 查看
Permission denied 文件权限不足 使用 chmodsudo
ambiguous redirect 文件名含有空格 使用双引号包裹变量
No such file or directory 文件不存在且无法创建 检查目录权限或路径拼写
Bad file descriptor 文件描述符编号错误 检查是否使用了非法编号如 3>

🧠 总结与小贴士

技巧 说明
> 是 Shell 的“输出控制器” 让你能自由指定输出去向
2> 是“错误处理器” 专门处理错误信息,便于调试
` ` 是“数据管道”
tee 是“双面镜” 显示输出的同时保存日志
<< 是“内嵌文档” 适合写模板、配置片段
推荐统一使用 bash 编写脚本 功能更强,兼容性更好
使用双引号包裹变量 防止空格或特殊字符出错

📚 推荐练习题(可选)

  1. 编写一个脚本,将系统当前时间、负载信息写入日志文件,并保留最近 5 条记录。
  2. 写一个脚本,循环执行 ping,并将失败的信息记录到日志中。
  3. 实现一个函数 log(),接收等级和消息参数,自动添加时间戳并写入日志文件。
  4. 编写一个脚本,将 top 命令运行 10 秒后自动退出,并将结果保存到文件。
  5. 创建一个菜单脚本,每次选择都会记录到日志文件中,并附带时间戳。
posted @ 2023-04-02 21:58  红尘过客2022  阅读(40)  评论(0)    收藏  举报