“这行命令跑了一晚,日志全丢了?”—— 5分钟彻底搞懂 Linux I/O 重定向与 tee 大法

1. 引言:午夜心碎时刻

你有没有经历过这样的场景:

临下班前,你写好了一个数据迁移脚本,在终端敲下命令,看着进度条开始跑,心满意足地回家了。 第二天一早,你满怀期待地打开电脑,发现终端窗口因为网络波动断开了(Broken Pipe),或者被系统的自动更新重启了。

结果: 屏幕上的日志没了,文件里也没存。脚本到底跑完了吗?报错了吗?在哪断的? 答案: 上帝才知道。

这就是**"数据流失"**的惨痛教训。

今天要讲的 >>>&tee,就是 Linux 世界里的管道工工具包。学会它们,你就能随心所欲地控制程序输出的去向------既能在屏幕上看"现场直播",又能把日志存进文件"录像回放"。


2. 概念拆解:Linux 的水管系统

在 Linux 的哲学里,"一切皆文件"。程序的输入输出,本质上就是三根水管。

核心三要素

我们把一个运行的程序想象成一台净水器

  1. 标准输入 (stdin, 0):进水管。通常是键盘输入,或者别的文件传进来的数据。

  2. 标准输出 (stdout, 1) :出水管(净水)。程序正常运行产生的打印信息,默认流向你的显示器

  3. 标准错误 (stderr, 2) :排污管(废水)。程序报错时的警告或错误信息,默认也流向你的显示器

符号图解

  • > (覆盖重定向) : 相当于把出水管从显示器上拔下来,插到一个桶(文件)里。 注意:每次都会先把桶倒空,再接水。

  • >> (追加重定向) : 也把出水管插到桶里。 区别:如果桶里原本有水,它不倒掉,直接接着往里灌。

  • | (管道): 把前一台净水器的出水管,直接接到下一台净水器的进水管。

  • tee (T型三通管) : 这就是神奇的神器。它是一个T型接头。水流过来,一份流向屏幕(让你看),一份分流进文件(存盘)。


3. 动手实战:从青铜到王者

我们先创建一个极简的脚本 demo.sh 来模拟真实场景。这个脚本会同时产生"正常日志"和"错误报错"。
Bash

复制代码
# demo.sh
# 模拟正常输出 (stdout)
echo "✅ [INFO] 处理数据块 1..."
echo "✅ [INFO] 处理数据块 2..."

# 模拟报错 (stderr) - 注意这里我们强制输出到 stderr
echo "❌ [ERROR] 连接数据库失败!" >&2

echo "✅ [INFO] 任务结束。"

场景一:初级------直接存文件 (>)

你只想把结果存起来,不关心屏幕看没看见。
Bash

复制代码
bash demo.sh > result.log
  • 结果

    • result.log 里只有 ✅ [INFO]...

    • 等等! 屏幕上居然打印了 ❌ [ERROR]...

  • 为什么?

    • 因为 > 默认只接管了 1号水管 (stdout)

    • 2号水管 (stderr) 依然指向屏幕,所以报错漏出来了,没存进文件里!

场景二:进阶------全量保存 (2>&1)

这是新手最头疼的符号。我们想把"报错"和"正常日志"都存进同一个文件。
Bash

复制代码
bash demo.sh > result.log 2>&1
  • 代码解析

    • > result.log:先把 1号管 接到文件。

    • 2>&1:这是一个"并管"操作。意思是:把 2号管 (stderr) 的出口,汇入到 1号管 (stdout) 当前的流向中。

    • 结果 :正常日志和报错都乖乖进了 result.log

场景三:王者------我全都要 (tee)

这就是解决引言中痛点的终极方案。既要在屏幕上监控进度,又要存文件备份。

Getty Images

我们需要一个 T型三通(Tee)。
Bash

复制代码
bash demo.sh | tee result.log
  • 发生了什么?

    • |:管道符,把 demo.sh 的输出传给 tee 命令。

    • tee:接收到数据后,左手画圆(打印到屏幕),右手画方(写入 result.log)

  • 注意tee 默认只接收 stdout。如果也要保存报错,需要先合并流:

Bash

复制代码
# 完美方案:标准输出+错误,既看屏幕,又存文件
bash demo.sh 2>&1 | tee result.log

场景四:不讲武德------追加模式 (tee -a & >>)

如果你不想覆盖昨天的日志,而是想接着写:

  • 普通重定向 :用 >> 代替 >

  • Tee 模式 :用 -a (append) 参数。

Bash

复制代码
bash demo.sh 2>&1 | tee -a result.log

4. 进阶深潜:那些你不知道的坑

坑 1:sudo 也不好使?

你可能遇到过这种情况:想把一段文本写入一个只有 root 权限才能写的文件(比如 /etc/profile)。
Bash

复制代码
# ❌ 错误示范
sudo echo "export JAVA_HOME=..." >> /etc/profile
# 报错: Permission denied

为什么? 因为 sudo 只对 echo 命令生效。后面的 >> 是由你当前的 Shell 执行的,而你的 Shell 没有权限写 /etc/profile

✅ 最佳实践 (使用 tee)
Bash

复制代码
echo "export JAVA_HOME=..." | sudo tee -a /etc/profile

这里 sudo 提升了 tee 的权限,tee 负责写文件,完美解决。为了不让屏幕多打印一遍,可以扔进黑洞:
Bash

复制代码
echo "data" | sudo tee file.txt > /dev/null

坑 2:2>&1 > file vs > file 2>&1

这两个命令看起来很像,但效果完全不同!顺序非常重要!

  1. 正确: > file 2>&1

    • 解释:先把 1 指向文件,然后把 2 指向 1(也就是文件)。

    • 结果:大家都在文件里。

  2. 错误: 2>&1 > file

    • 解释:先把 2 指向 1(此时 1 还在屏幕),所以 2 去了屏幕。然后把 1 指向文件。

    • 结果:报错打在了屏幕上,只有正常日志进了文件。


5. 总结与延伸

一句话总结

  • > 是"洗心革面"(覆盖文件)。

  • >> 是"再续前缘"(追加文件)。

  • 2>&1 是"兄弟齐心"(错误流汇入标准流)。

  • tee 是"分身有术"(屏幕和文件我都要)。

相关推荐
dingdingfish5 小时前
Bash 学习 - 第1章:Introduction
bash·shell·programming·introduction
pr_note2 天前
legality检查
shell·tcl
啥都不懂的小小白3 天前
Shell脚本编程入门:从零基础到实战掌握
前端·shell
dingdingfish7 天前
GNU Parallel 学习 - 第1章:How to read this book
bash·shell·gnu·parallel
似霰10 天前
Linux Shell 脚本编程——核心基础语法
linux·shell
似霰10 天前
Linux Shell 脚本编程——脚本自动化基础
linux·自动化·shell
偷学技术的梁胖胖yo11 天前
Shell脚本中连接数据库查询数据报错 “No such file or directory“以及函数传参数组
linux·mysql·shell
纵有疾風起20 天前
【Linux 系统开发】基础开发工具详解:软件包管理器、编辑器。编译器开发实战
linux·服务器·开发语言·经验分享·bash·shell
gis分享者22 天前
Shell 脚本中如何使用 here document 实现多行文本输入? (中等)
shell·脚本·document·多行·文本输入·here
柏木乃一22 天前
基础IO(上)
linux·服务器·c语言·c++·shell