You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含sed的脚本执行时输出重定向异常,终端与日志内容不一致求助

问题背景

文件结构:

- script.sh
- directory (空目录)

script.sh代码:

#!/bin/bash
echo "Start"

find . -type f | xargs sed -r -i '' "s/a/b/g"

echo 'After find/sed'

在directory目录中执行命令:../script.sh | tee out.log,得到以下结果:

  • 终端输出:
Start
After find/sed
  • cat out.log输出:
Stbrt

提出两个问题:

  1. 为何终端输出与out.log内容不同?
  2. 脚本如何影响out.log的内容?它不是应该在脚本执行完成后才创建吗?(可见已被修改:Start变为Stbrt)

问题解答

1. 终端输出与out.log内容不同的原因

执行../script.sh | tee out.log时,tee会同时将脚本输出写入终端和out.log,但流程中存在文件替换的干扰:

  • 首先echo "Start"的输出被tee写入终端和out.log,此时out.log内容为Start\n。
  • 接着脚本执行find . -type f,会遍历当前的directory目录,此时out.log已经被tee创建,会被find捕获并传给xargs sed。
  • 你的环境是BSD sed(比如macOS默认),sed -i ''会创建临时文件,把替换后的内容写入临时文件,再删除原out.log,将临时文件重命名为out.log。这时候tee之前打开的是旧的out.log文件句柄,后续echo 'After find/sed'的输出会写入那个已经被删除的旧文件(内核会保留它直到tee结束,但用户看不到)。
  • 终端是实时输出内容,所有信息都会直接显示;但你最终cat out.log看到的是sed替换后的新文件,里面只有被改成Stbrt的第一行内容,第二行输出根本没写入到这个新文件里。

2. 脚本如何影响out.log,以及文件创建时机

tee命令在管道启动的瞬间就会创建out.log,不是等脚本执行完才生成。当你运行command | tee file时,tee会先打开目标文件(不存在则创建),然后才开始接收管道内容。

脚本里的find命令会扫描当前目录下的所有普通文件,这时候out.log已经存在,所以会被纳入处理范围。随后sed的替换规则s/a/b/g会把文件里的a换成b,Start就变成了Stbrt。再加上前面说的sed -i替换文件的机制,导致后续的输出无法写入最终的out.log,最终文件里只剩修改后的第一行。


内容的提问来源于stack exchange,提问作者mouse_00

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:25:25