Node.js 16中package.json脚本stdout重定向异常:swagger.schema.json仅生成半量内容问题排查
Why does
sed > file truncate output at 32768 bytes, but tee file works in yarn scripts? 这是个典型的子进程I/O缓冲+进程生命周期管理问题,咱们结合你的场景具体分析:
1. 原命令的问题根源
你的schema:replace脚本是:
cat dist/tmpschema | sed 's:#/definitions/:#/components/schemas/WireMessage/definitions/:g' >dist/swagger.schema.json
这里的核心问题出在两个点:
- 全缓冲机制:当
sed的输出目标是文件(而非终端)时,默认会启用全缓冲——也就是只有当输出缓冲区被填满(通常是32KB,正好是你看到的2^15字节),或者进程正常退出时,才会把缓冲区的内容写入文件。 - yarn的进程组管理:yarn作为脚本的父进程,在管理子进程时,可能会在管道中某个上游进程(比如
cat,它读完文件后会很快退出)结束后,误判整个schema:replace脚本已经执行完成,提前向sed进程发送终止信号。此时sed可能还在处理剩余数据,缓冲区里未填满的内容还没来得及写入文件,就被强制终止了,最终文件只保留了刚好填满一次缓冲的32KB内容。
2. 为什么tee能解决问题?
当你换成:
cat dist/tmpschema | sed 's:...:g' | tee dist/swagger.schema.json >/dev/null
tee的存在改变了整个管道的行为:
tee的设计目标是转发输入到多个输出,它会持续监听输入流直到收到EOF(文件结束符),才会终止进程。在终止前,tee会强制刷新所有剩余的缓冲区内容到目标文件,不会丢失数据。- 同时,yarn会看到
tee进程还在运行(因为它在等待sed的全部输出),不会提前发送终止信号,确保sed能完整处理所有数据,tee能把所有内容写入文件。
额外验证小技巧
你也可以通过强制sed使用行缓冲来解决问题,比如:
cat dist/tmpschema | sed -u 's:#/definitions/:#/components/schemas/WireMessage/definitions/:g' >dist/swagger.schema.json
这里的-u参数让sed启用行缓冲,每处理完一行就立即写入文件,这样即使进程被提前终止,丢失的也只是最后一行内容(而不是整个缓冲块)。不过tee的方案更可靠,因为它从进程生命周期层面避免了提前终止的问题。
内容的提问来源于stack exchange,提问作者Henrik
相关产品推荐
相关产品推荐

