linux tee命令

命令简介

tee 命令用于从标准输入读取数据,并同时将数据写入标准输出和指定的文件。它就像水管工使用的 T 型管接头,可以将数据流同时导向多个方向,是 Linux 管道操作中非常重要的工具。

特点: tee 命令能够在不中断数据流的情况下,将数据同时输出到屏幕和文件,非常适合调试、日志记录和数据处理。

语法

tee [选项] [文件...]

常用形式:

# 基本用法
命令 | tee 文件

# 写入多个文件
命令 | tee 文件1 文件2 文件3

# 追加到文件
命令 | tee -a 文件

常用选项

选项 说明
-a 追加到文件,而不是覆盖
-i 忽略中断信号
-p 诊断写入非管道的错误
--help 显示帮助信息
--version 显示版本信息

基本用法

1. 基本输出和保存
# 查看文件内容并保存到日志文件
cat important.txt | tee output.log

# 查看进程信息并保存
ps aux | tee process_info.txt

# 同时查看和保存命令输出
ls -la | tee directory_listing.txt
2. 追加到文件
# 追加到文件而不是覆盖
echo "新的日志条目" | tee -a app.log

# 多次追加日志
date | tee -a system_log.txt
who | tee -a system_log.txt
uptime | tee -a system_log.txt

# 查看追加结果
tail -5 system_log.txt
3. 写入多个文件
# 同时写入多个文件
ls -l | tee file1.txt file2.txt file3.txt

# 验证所有文件内容相同
diff file1.txt file2.txt
diff file2.txt file3.txt

# 同时写入日志文件和备份文件
df -h | tee disk_usage.log disk_backup.txt
4. 在管道中间使用
# 在复杂管道中保存中间结果
cat data.txt | grep "error" | tee errors.txt | wc -l

# 处理数据并保存原始输出
cat numbers.txt | tee raw_data.txt | sort | uniq > unique_numbers.txt

# 查看处理前后的数据
echo -e "3\n1\n2\n3\n1" | tee original.txt | sort | uniq > sorted.txt

实际应用场景

场景1:脚本调试和日志记录
#!/bin/bash
# 使用tee记录脚本执行过程

LOG_FILE="script_$(date +%Y%m%d_%H%M%S).log"

echo "脚本开始执行..." | tee "$LOG_FILE"
echo "当前时间: $(date)" | tee -a "$LOG_FILE"

# 执行命令并记录输出
ls -la | tee -a "$LOG_FILE"
df -h | tee -a "$LOG_FILE"

echo "脚本执行完成" | tee -a "$LOG_FILE"
echo "日志文件: $LOG_FILE"
场景2:系统监控和报警
#!/bin/bash
# 监控系统状态并记录

MONITOR_LOG="/var/log/system_monitor.log"
ALERT_THRESHOLD=80

# 检查磁盘使用率
df -h | grep -v tmpfs | tee -a "$MONITOR_LOG" | awk '
$5 > '"$ALERT_THRESHOLD"' {
    print "警告: 磁盘 " $1 " 使用率 " $5 " > '"$ALERT_THRESHOLD"'%"
}'

# 检查内存使用
free -h | tee -a "$MONITOR_LOG" | grep Mem | awk '
$3/$2 * 100 > '"$ALERT_THRESHOLD"' {
    print "警告: 内存使用率 > '"$ALERT_THRESHOLD"'%"
}'
场景3:安装和配置过程记录
# 记录软件安装过程
sudo apt update | tee install.log
sudo apt install nginx -y | tee -a install.log

# 配置服务并记录
sudo systemctl enable nginx | tee -a install.log
sudo systemctl start nginx | tee -a install.log

# 验证安装
nginx -v | tee -a install.log
echo "安装完成,详细日志见 install.log"
场景4:数据备份和验证
#!/bin/bash
# 备份数据并验证

BACKUP_SRC="/home/user/documents"
BACKUP_DEST="/backup/documents_$(date +%Y%m%d).tar.gz"
LOG_FILE="/var/log/backup.log"

echo "开始备份: $(date)" | tee -a "$LOG_FILE"

# 创建备份并记录过程
tar -czf "$BACKUP_DEST" "$BACKUP_SRC" 2>&1 | tee -a "$LOG_FILE"

# 验证备份文件
if [ -f "$BACKUP_DEST" ]; then
    echo "备份成功: $BACKUP_DEST" | tee -a "$LOG_FILE"
    echo "文件大小: $(du -h "$BACKUP_DEST" | cut -f1)" | tee -a "$LOG_FILE"
else
    echo "备份失败!" | tee -a "$LOG_FILE"
    exit 1
fi

echo "备份完成: $(date)" | tee -a "$LOG_FILE"

高级用法

1. 使用进程替换
# 同时将输出发送到多个命令处理
ls -la | tee >(grep ".txt" > txt_files.txt) >(grep ".log" > log_files.txt) > all_files.txt

# 验证结果
wc -l *.txt
# 输出:
# 15 all_files.txt
# 3 log_files.txt
# 5 txt_files.txt
2. 实时监控和记录
# 实时监控日志并记录特定事件
tail -f /var/log/syslog | tee full_log.txt | grep -i "error" > errors.txt

# 在另一个终端查看错误
# tail -f errors.txt

# 监控网络连接并记录
netstat -tulpn | tee network_connections.txt | grep LISTEN
3. 复杂管道调试
#!/bin/bash
# 调试复杂的数据处理管道

INPUT_FILE="data.csv"
DEBUG_LOG="debug.log"

echo "开始数据处理..." | tee "$DEBUG_LOG"

# 在管道的每个阶段保存中间结果
cat "$INPUT_FILE" | \
tee raw_data.txt | \
grep -v "^#" | \
tee cleaned_data.txt | \
awk -F, '{print $1 "," $3}' | \
tee selected_columns.txt | \
sort | \
tee sorted_data.txt | \
uniq > final_result.txt

echo "数据处理完成" | tee -a "$DEBUG_LOG"
echo "中间文件已保存用于调试" | tee -a "$DEBUG_LOG"
4. 权限提升操作记录
#!/bin/bash
# 使用sudo记录特权操作

AUDIT_LOG="/var/log/sudo_audit.log"
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")

echo "=== Sudo操作审计 ===" | sudo tee -a "$AUDIT_LOG"
echo "时间: $TIMESTAMP" | sudo tee -a "$AUDIT_LOG"
echo "用户: $(whoami)" | sudo tee -a "$AUDIT_LOG"
echo "命令: $@" | sudo tee -a "$AUDIT_LOG"

# 执行命令并记录输出
sudo "$@" 2>&1 | sudo tee -a "$AUDIT_LOG"

echo "=== 操作结束 ===" | sudo tee -a "$AUDIT_LOG"

输入输出重定向技巧

1. 处理标准错误
# 同时捕获标准输出和标准错误
ls -la /root /nonexistent 2>&1 | tee output.log

# 分别处理标准输出和标准错误
(ls -la /root | tee stdout.log) 2>&1 | tee stderr.log

# 合并输出但分别标记
{
    echo "=== 标准输出 ==="
    ls -la /etc/passwd
    echo "=== 标准错误 ==="
    ls -la /nonexistent
} 2>&1 | tee combined.log
2. 使用文件描述符
# 使用不同的文件描述符
exec 3>&1  # 保存标准输出到文件描述符3
ls -la | tee log.txt | cat >&3  # 同时输出到文件和屏幕

# 复杂的重定向
{
    echo "开始任务..."
    find /etc -name "*.conf" 2>/dev/null
    echo "任务完成"
} | tee task.log | grep "\.conf" > conf_files.txt

与其他命令的比较

命令 功能 适用场景
tee 双向数据流 同时输出到屏幕和文件,管道中间保存数据
> 重定向 输出到文件 简单地将输出保存到文件,不显示在屏幕
| 管道 连接命令 将一个命令的输出作为另一个命令的输入
script 记录整个会话 记录终端的所有输入输出
tail -f 实时查看文件 监控文件变化,但不修改文件

实用技巧

  • 使用 tee -a 追加日志,避免覆盖重要数据
  • 在复杂管道中使用 tee 保存中间结果,便于调试
  • 结合 2>&1 可以同时捕获标准输出和标准错误
  • 使用进程替换 tee >(command) 可以实现复杂的数据分流
  • 在脚本开头使用 exec > >(tee log.txt) 可以自动记录所有输出
  • 使用 sudo tee 可以将输出写入需要特权访问的文件
  • 结合 timestamp 命令可以为日志添加时间戳

注意事项

  • tee 默认会覆盖目标文件,使用 -a 选项追加
  • 如果目标文件不可写,tee 会报错并停止
  • tee 会保持数据的顺序,但性能可能受最慢的输出影响
  • 在管道中使用多个 tee 命令时,注意磁盘空间
  • 使用 sudo tee 时,确保有适当的文件权限
  • 在生产环境中,注意日志文件的大小和轮转
  • tee 不会缓存大量数据,适合流式处理