Bash中如何将管道内首个失败命令的stderr输出保存到变量
Bash捕获管道中首个命令的stderr到变量的实现方法
问题原因说明
你之前的两种写法都不生效的原因是:
error_message=$(cmd1 2>&1|cmd2):将cmd1的stderr和stdout合并后全部传入管道交给cmd2处理,最终你捕获到的还是cmd2的输出内容error_message=$(cmd1|cmd2 2>&1):仅合并了cmd2的stderr和stdout,cmd1的stderr会直接输出到终端,完全不会被变量捕获
实现方案
方案1:自定义文件描述符隔离流(推荐,无临时文件开销)
通过额外的文件描述符单独导流cmd1的stderr,避免和其他输出混淆:
# 示例中cmd1为curl,cmd2为echo "hello" declare error_message # 备份当前标准输出到文件描述符3 exec 3>&1 # 单独捕获cmd1的stderr到变量,cmd2的输出正常打印到终端 error_message=$( { curl https://example.invalid 2>&1 >&3 | echo "hello"; } ) # 关闭临时文件描述符3 exec 3>&-
执行后如果curl请求失败,error_message会存储curl的报错信息,cmd2输出的hello会正常打印到终端,不会进入变量。
方案2:配合PIPESTATUS判断命令执行状态
如果需要同时确认管道中各个命令的执行结果,可以使用Bash内置的PIPESTATUS数组获取每个命令的退出码:
# 执行完管道命令后立即读取,否则会被后续命令的退出码覆盖 cmd1_exit_code=${PIPESTATUS[0]} cmd2_exit_code=${PIPESTATUS[1]} # 示例:仅当cmd1执行失败时处理错误信息 if [ $cmd1_exit_code -ne 0 ]; then echo "cmd1执行失败,错误信息:$error_message" fi
内容的提问来源于stack exchange,提问作者SuperAadi
相关产品推荐
相关产品推荐

