0%

重定向

Shell 重定向详解:从标准流到 tee 命令的完整指南

在 Shell 中,输入输出重定向是控制命令数据流的核心机制,通过灵活处理标准输入(stdin)、标准输出(stdout)和标准错误(stderr),可以实现日志记录、错误屏蔽、批量处理等多种功能。本文将系统讲解重定向的原理、用法及 tee 命令的应用。

标准流与文件描述符

Shell 中所有命令的输入输出都基于三个标准流,每个流对应一个文件描述符(用于在系统中标识流):

标准流 功能描述 文件描述符 默认设备
stdin 标准输入(命令读取数据) 0 键盘
stdout 标准输出(命令正常输出) 1 终端屏幕
stderr 标准错误(命令错误输出) 2 终端屏幕

这些流可以被重定向到文件、设备或其他命令,改变数据的默认流向。

输入重定向(<

输入重定向用于将命令的输入来源从默认的键盘改为指定文件,语法为:
命令 < 输入文件

常用场景

  • 批量输入数据(如给 mail 命令提供邮件内容);
  • 替代管道传递文件内容(等价于 cat 输入文件 | 命令)。

示例

1
2
3
4
5
6
7
8
# 从 file.txt 中读取内容作为 grep 的输入(查找包含 "hello" 的行)
grep "hello" < file.txt

# 从 input.txt 中读取数据作为 wc 的输入(统计行数)
wc -l < input.txt

# 向 mail 命令输入邮件内容(内容来自 message.txt)
mail -s "测试邮件" user@example.com < message.txt

输出重定向(>>>2>2>>

输出重定向用于将命令的输出(正常或错误)写入文件,而非终端。根据流类型和操作方式,分为以下几种:

标准输出重定向

  • 命令 > 文件:将标准输出覆盖写入文件(文件不存在则创建,存在则清空)。
  • 命令 >> 文件:将标准输出追加写入文件(保留原有内容)。

示例

1
2
3
4
5
# 覆盖写入:将当前目录列表保存到 dir.txt
ls -l > dir.txt

# 追加写入:将系统时间追加到 time.log
date >> time.log

标准错误重定向

错误输出需要显式指定文件描述符 2

  • 命令 2> 文件:将标准错误覆盖写入文件。
  • 命令 2>> 文件:将标准错误追加写入文件。

示例

1
2
3
4
5
# 捕获错误信息:删除不存在的文件,错误写入 error.log
rm no_such_file 2> error.log

# 追加错误:连续执行错误命令,错误信息累加
ls invalid_dir 2>> error.log

合并输出重定向

实际场景中常需要将标准输出和错误输出合并处理,有两种常用方式:

(1)2>&1:将错误输出重定向到标准输出
  • 语法:命令 > 文件 2>&1(先重定向 stdout 到文件,再将 stderr 指向 stdout)。
  • 追加形式:命令 >> 文件 2>&1

示例

1
2
3
4
5
# 将所有输出(正常+错误)覆盖写入 all.log
./script.sh > all.log 2>&1

# 将所有输出追加到 all.log
./script.sh >> all.log 2>&1
(2)&>>&:简化的合并写法
  • 命令 &> 文件:等价于 命令 > 文件 2>&1(Bash 扩展语法)。
  • 命令 &>> 文件:等价于 命令 >> 文件 2>&1

示例

1
2
3
4
5
# 合并输出到 log.txt(覆盖)
curl http://example.com &> log.txt

# 合并输出追加到 log.txt
curl http://example.com &>> log.txt

特殊重定向目标

/dev/null:屏蔽输出

  • 被称为 “黑洞设备”,所有写入的数据都会被丢弃,常用于屏蔽不需要的输出。

示例

1
2
3
4
5
# 屏蔽所有输出(包括错误)
rm no_such_file &> /dev/null

# 只屏蔽错误输出,保留正常输出
ls -l 2> /dev/null

/dev/tty:强制输出到终端

  • 表示当前终端设备,即使标准输出已被重定向,仍会显示在屏幕上。

示例

1
2
3
# 正常输出写入文件,但提示信息显示在终端
echo "开始执行备份..." > /dev/tty
tar -czf backup.tar.gz data/ > backup.log 2>&1

tee 命令:输出分流工具

1
2
tee` 命令用于将输入数据同时发送到**标准输出(终端)****指定文件**,实现 “一份输入,多处输出” 的效果,语法为:
`命令 | tee [选项] 文件

常用选项

  • -a:追加模式(默认是覆盖模式)。
  • --append:同 -a

示例

1
2
3
4
5
6
7
8
9
# 同时在终端显示日期并写入 time.log(覆盖)
date | tee time.log

# 同时在终端显示命令输出并追加到 output.log
ls -l | tee -a output.log

# 结合管道和重定向:过滤日志并分流
cat app.log | grep "error" | tee error.log 2>&1 > /dev/null
# 说明:将过滤出的错误日志同时写入 error.log 和终端

典型应用:日志实时查看与保存

1
2
# 实时跟踪日志文件,同时保存到 archive.log
tail -f app.log | tee -a archive.log

重定向的优先级与注意事项

  1. 重定向顺序

    • 输出重定向中,> 应在 2>&1 之前(如 > file 2>&1 正确,2>&1 > file 错误)。
    • 输入重定向 < 通常放在命令末尾。
  2. 文件权限
    重定向写入文件时,需确保当前用户对目标文件有写权限,否则会报错 Permission denied

  3. 子 Shell 影响
    管道中的命令在子 Shell 中执行,重定向仅影响子 Shell,不改变父 Shell 的环境:

    1
    2
    3
    # 错误示例:管道中的变量赋值在父Shell中无效
    echo "123" | read num
    echo $num # 输出为空(num在子Shell中定义)
  4. Here Document( heredoc )
    一种特殊的输入重定向,用于在脚本中嵌入多行输入:

    1
    2
    3
    4
    5
    6
    # 将多行文本写入 file.txt
    cat > file.txt << EOF
    第一行内容
    第二行内容
    EOF
    # 说明:<< EOF 表示从下一行开始读取,直到遇到 EOF 结束

欢迎关注我的其它发布渠道