如何让管道在前置命令失败时彻底终止?防止JSON文件被误清空
原地格式化JSON文件时避免因解析错误清空文件
我之前用这条命令原地格式化JSON文件:
jq . foo.json | sponge foo.json
它能正常完成格式化,但有个致命问题:如果jq . foo.json执行失败(比如JSON解析错误),管道还是会继续执行,导致foo.json被写入空内容直接清空。
我需要的是:只有当jq执行成功时,才让后续命令处理并覆盖原文件;如果jq失败,原文件保持原样。比如:
- 对于格式合法的输入:
希望格式化后变成:"foo""foo" - 对于格式错误的输入(比如未闭合的字符串):
希望原文件保持不变,而不是被清空。"foo
简便解决方案
方法1:临时文件中转(最稳妥直观)
用临时文件先保存jq的处理结果,只有jq执行成功时,再用临时文件替换原文件:
jq . foo.json > foo.tmp && mv foo.tmp foo.json
逻辑很简单:&&是短路运算符,只有前面的jq命令返回成功状态码(0)时,才会执行后面的mv命令。如果jq解析失败,临时文件会保留错误输出(或空内容),但原文件不会被修改。
如果担心临时文件残留,可以加上自动清理逻辑:
trap 'rm -f foo.tmp' EXIT jq . foo.json > foo.tmp && mv foo.tmp foo.json
trap会在脚本退出时自动删除临时文件。
方法2:利用PIPESTATUS判断管道前序命令状态
在bash中,可以通过PIPESTATUS数组获取管道中每个命令的退出状态,只在jq成功时执行sponge:
jq . foo.json | { [[ ${PIPESTATUS[0]} -eq 0 ]] && sponge foo.json; }
${PIPESTATUS[0]}对应管道中第一个命令(也就是jq)的退出码,等于0说明执行成功,此时才会调用sponge写入原文件。
效果验证
- 处理合法JSON时,两种方法都能正常格式化并覆盖原文件;
- 处理非法JSON时,
jq会输出解析错误,后续的mv或sponge都不会执行,原文件内容保持不变。
内容的提问来源于stack exchange,提问作者Mason
相关产品推荐
相关产品推荐

