git命令输出刷新后仍可获取错误码的实现方法求助
解决实时输出刷新与保留原命令错误码的问题
我完全懂你碰到的这个棘手情况:想要让命令输出实时刷新,同时还能拿到原命令的错误码,但stdbuf不管用,用tee能实现刷新却丢了错误码。结合你提到的Git 2.11.0场景,我来拆解下问题和可行的解决方案:
为什么tee会丢失错误码?
默认情况下,Shell执行管道命令时,只会返回最后一个命令的退出码。比如你用git fetch ... | tee ...,$?拿到的是tee的退出码,而不是git fetch的,这就是错误码丢失的核心原因。
如何保留原命令的错误码?
有两种实用方法可以解决这个问题:
方法1:用Bash的PIPESTATUS数组
Bash提供了PIPESTATUS数组,它会记录管道中每个命令的退出码,索引对应命令在管道中的位置。第一个命令的退出码就存在${PIPESTATUS[0]}里:
git fetch --all 2>&1 | tee stderr.txt > /dev/null # 获取git fetch的退出码 GIT_EXIT_CODE=${PIPESTATUS[0]} # 可以根据这个码做后续处理,比如让脚本返回原错误码 exit $GIT_EXIT_CODE
方法2:开启pipefail选项
如果你希望整个管道的退出码直接等于第一个失败命令的退出码,可以先开启pipefail选项(Bash和Zsh都支持):
# 开启pipefail选项 set -o pipefail # 执行目标命令 git fetch --all 2>&1 | tee stderr.txt > /dev/null # 此时$?就是git fetch的退出码 GIT_EXIT_CODE=$?
这个选项的作用是:如果管道中有任何一个命令失败,整个管道的退出码就等于第一个失败命令的退出码,而不是最后一个命令的。
为什么stdbuf没效果?
你提到用stdbuf -o0 -e0没奏效,这是因为Git自己实现了输出缓冲逻辑,没有依赖C标准库的缓冲机制。stdbuf只能修改标准库的缓冲行为,对Git这种自己处理缓冲的程序完全无效。所以tee确实是更可靠的实时输出方案——因为tee默认是行缓冲的,会把接收到的内容立刻输出,绕过Git的内部缓冲。
另外你说即使不重定向stderr问题依然存在,这也印证了Git的缓冲是全局控制的,不管stdout还是stderr,都会被它自己的逻辑处理,所以stdbuf无法干预。
内容的提问来源于stack exchange,提问作者jeb
相关产品推荐
相关产品推荐

