AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

tee —— 一边输出、一边写文件

一句话定义

tee 把 stdin 同时输出到 stdout(屏幕)+ 写入文件。名字来自 T 字形管道——一进、二出。在脚本里"看着跑 + 留日志"是它的核心场景。

典型场景

  • 看长跑命令的输出 + 同时写日志:cmd | tee log.txt
  • sudo 写权限:echo "..." | sudo tee /etc/x.conf
  • 同时写多个文件
  • 流式追加(K8s 装机脚本里很常见)

基础

echo "hello" | tee file.txt
# 屏幕显示 hello
# file.txt 内容 = hello
# 写多个文件
echo "hello" | tee file1.txt file2.txt file3.txt
# 实时看长跑 + 留日志
make build | tee build.log
helm install ... | tee install.log

-a 追加(不是覆盖)

echo "line1" | tee file.txt                       # 覆盖
echo "line2" | tee -a file.txt                    # 追加

-a = append,类似 >>。

cat file.txt
# line1
# line2

sudo tee —— 写需要 root 权限的文件

经典坑:

sudo echo "x" > /etc/some.conf
# bash: /etc/some.conf: Permission denied

echo 有 sudo 权限、但 > 是 shell 在做(非 root shell),还是被拒。

修:

echo "x" | sudo tee /etc/some.conf
# tee 拿到 sudo 权限、写文件 OK
# 同时屏幕也显示 "x"

echo "x" | sudo tee -a /etc/some.conf             # 追加
echo "x" | sudo tee /etc/some.conf > /dev/null    # 不要屏幕回显

这是 tee 在运维场景的最主要用法。


写到 stderr(少见但有用)

echo "warning" | tee /dev/stderr | grep -v xxx
# tee 同时把 warning 输出到 stderr
# stdout 继续往下游 grep

-i 忽略 SIGINT

long-command | tee log.txt
# Ctrl-C → tee 也死、可能丢最后一行
long-command | tee -i log.txt
# tee 忽略 SIGINT,让上游 command 自己处理 Ctrl-C

主要用于"长跑命令 + 想保证日志写完整"。


实战例子

1. 装机脚本里"写配置 + 显示"

cat <<'EOF' | sudo tee /etc/sysctl.d/99-k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
# 配置写进去了、屏幕也显示了一遍(提供 audit trail)

2. 跑测试 + 留日志

make test | tee test-$(date +%F).log

或者并行:

make test 2>&1 | tee test.log                     # stderr 也捕获

3. K8s 部署 + 留 trail

helm upgrade -i my-app ./chart -f values.yaml 2>&1 | tee deploy.log
# 既看屏幕、又留 deploy.log 排查

4. 给追加配置 + 显示

echo "Host m1" | sudo tee -a ~/.ssh/config
# 屏幕显示 + 追加到 config

5. 接管 ssh 的输出

ssh m1 'kubectl get pods -A' | tee pods-snapshot.txt
# 把远端命令输出留本地

6. 中间观察 + 不影响管道

kubectl get pods | tee /tmp/pods.txt | grep -c Running
# 既看到完整列表保存到文件、又能继续 grep 计数

tee 在中间是透明的——不改变管道数据流。

7. 同时写本地 + 远程文件

echo "log entry" | tee >(ssh m1 'cat >> /var/log/remote.log') >> /var/log/local.log
# 进程替换 + tee 同时本地 + ssh 远程

复杂但能用。


进程替换 >(...) 配合 tee

echo "data" | tee >(command1) >(command2) > output.txt
# tee 把 data 同时给:
#   - command1 的 stdin
#   - command2 的 stdin
#   - output.txt 文件

K8s 经典:同时给多个处理器:

journalctl -u kubelet -f \
  | tee >(grep ERROR > errors.log) \
        >(grep WARN > warns.log) \
        > all.log

一份 stdin、三路输出。


常见踩坑

坑 1:> 没 sudo 权限

sudo echo "x" > /etc/x.conf
# Permission denied

经典错误。改 tee:

echo "x" | sudo tee /etc/x.conf

坑 2:默认覆盖、想追加忘加 -a

echo "line1" | tee file.txt
echo "line2" | tee file.txt                       # ❌ 覆盖了 line1
echo "line2" | tee -a file.txt                    # ✅

坑 3:stderr 没捕获

make build | tee build.log
# 但 build error 没在 log 里(错误走 stderr)
make build 2>&1 | tee build.log
# 2>&1 把 stderr 合并到 stdout

坑 4:管道在 strict mode 行为

set -o pipefail
fails-cmd | tee log
# tee 成功 → 整个管道退出码看 fails-cmd

pipefail 让管道任一失败就整体失败。tee 总是 0、是中性的。

坑 5:写多个文件、权限不同

echo "x" | sudo tee /etc/file1 /home/user/file2
# /etc/file1 owner = root(OK)
# /home/user/file2 owner = root(用户的家、不应该 root 拥有)

要分两步:

echo "x" | sudo tee /etc/file1
echo "x" | tee /home/user/file2

坑 6:tee 输出到 fifo / pipe 卡住

cmd | tee >(slow-consumer)
# tee 写到 slow-consumer 慢、整个管道卡

>(...) 子进程慢会反向 backpressure。要异步:

cmd | tee >(slow-consumer &)

或者用文件中转。

坑 7:tee 不能进容器 / 不能 ssh

echo "x" | tee | ssh m1 "cat >> /etc/file"
# 这里 tee 没意义、可以直接 |

tee 的价值是同时写文件 + 继续管道。单纯传输用 | 或 ssh ... < /file。


关联命令

  • > / >> —— shell 自带 redirect(写一个文件、不显示)
  • script —— 录制整个 shell session(更全面的"tee")
  • xargs —— xargs 之后 tee 留日志
  • mktemp —— 配合 tee 写临时文件
  • multitail —— 同时跟多个日志
在 GitHub 上编辑此页