file.txt;2>&1必须置于>之后,否则stderr无法捕获。 重定向符号写错顺序会直接执行失败 Linux 里 > ..."/>

Linux shell 输入输出重定向技巧

15次阅读

重定向符号顺序错误会导致执行失败:如 > file.txt hello.txt 将字面量 ”hello.txt” 写入而非读取文件;正确应为 cat hello.txt > file.txt;2>&1 必须置于 > 之后,否则 stderr 无法捕获。

Linux shell 输入输出重定向技巧

重定向符号写错顺序会直接执行失败

Linux 里 > 看似对称,但位置错了命令就不是你想要的——比如 <code>cat > file.txt hello.txt 不会把 hello.txt 内容写进 file.txt,而是把字面量 hello.txt 当作字符串输出进去。因为 shell 把 > 后面紧挨的内容当成目标文件,其余参数全当 cat 的输入参数(而 cat 没指定输入源时读 stdin)。

正确写法是:cat hello.txt > file.txtcat file.txt。注意: 必须紧跟在命令后或参数之间,不能塞在中间;<code>>>> 只能出现在命令行末尾或重定向链中靠后位置。

  • 2>&1 要写在 > 后面,否则 stderr 不会被捕获:用 command > out.txt 2>&1,别写成 command 2>&1 > out.txt(后者 2>&1 指向的是原始 stdout,还没被重定向)
  • 2>/dev/null 单独使用没问题,但和 > 组合时,顺序错会导致静默丢数据
  • bash 4.0+ 支持 &>file 简写等价于 >file 2>&1,但老系统或 dash/sh 下不认,别无脑用

exec 持久重定向整个 shell 会话

临时重定向只影响单条命令,想让后续所有命令输出都进日志?得靠 exec。它不是执行新进程,而是修改当前 shell 的 fd 映射——所以生效后连 echols 都走新路径。

常见误操作是漏掉 fd 编号或搞混方向:exec > log.txt 把 stdout(fd 1)重定向到文件;exec 3>tmp.txt 是开一个新 fd 3,不干扰默认流;exec 2>&1 才是把 stderr 接到当前 stdout(此时若 stdout 已被重定向,stderr 就也进去了)。

  • 要同时重定向 stdout 和 stderr 到同一文件:先 exec > log.txt,再 exec 2>&1(顺序不能反)
  • 恢复默认终端输出:用 exec > /dev/tty 2>/dev/tty,别试 exec > /dev/stdout——那只是个符号链接,可能已被改写
  • 脚本开头加 exec 3>&1 可保存原始 stdout,之后用 echo "debug" >&3 输出到终端,不影响主流程重定向

tee 分流时 -a 参数决定是否覆盖

tee 看似简单,但默认行为是覆盖文件,跟 > 一样;想追加得显式加 -a。很多人写 cmd | tee log.txt,跑两次后发现只有第二次结果——因为第一次的 log 被清空了。

另一个坑是管道中断导致 tee 提前退出,上游命令却还在写,可能触发 SIGPIPE。比如 yes | tee /tmp/junk.txt,手动 killall teeyes 进程常卡住不动(实际是被信号终止,但现象像卡死)。

  • 需要追加日志:用 cmd | tee -a log.txt,别依赖默认行为
  • 既要屏幕输出又要存两份不同格式?cmd | tee log.txt | grep "ERROR" —— 注意 tee 的 stdout 是管道,不是终端,所以第二段命令才能继续处理
  • 避免 tee 成为瓶颈:大数据量时加 --output-error=exit 让它出错立刻报,而不是默默丢数据

重定向到不存在目录会报错,mkdir -p 不能自动补救

command > /path/to/log/file.log 前,shell 不会帮你建中间目录。报错不是 No such file or directory,而是更迷惑的 No such file or directory(提示的是文件路径整体不可写),新手常以为是权限问题,其实只是 /path/to/log/ 根本不存在。

有人想用 mkdir -p $(dirname /path/to/log/file.log); command > /path/to/log/file.log,但要注意 $(dirname ……) 在重定向解析前就执行了,如果路径含变量或命令替换,得用子 shell 或提前展开。

  • 安全做法:先 mkdir -p /path/to/log,再重定向;或者用 set -o pipefail 配合 if 判断目录是否存在
  • 脚本里别写 command > $(mktemp) 就完事——临时文件没清理,且 mktemp 返回路径带换行或空格时会崩
  • zsh 用户注意:cd foo && command > ../bar/out.log 中的 ../bar 是相对于原工作目录还是当前?答案是原目录——重定向路径解析不随 cd 实时更新

重定向看着只是加几个符号,但 fd 层、shell 解析顺序、子进程继承规则全在底下咬着。最常翻车的地方不是语法记错,而是以为“它该懂我的意图”,结果它只认字面意思。

text=ZqhQzanResources