bash脚本中某步骤失败时的退出码问题
兄弟,我来帮你把这个问题掰明白:
首先说默认情况——你的脚本现在是依次执行call01、call02这些命令,但bash默认不会因为某个命令失败就终止整个脚本,哪怕这个命令是被OS因内存不足杀死的。除非你做了特殊设置,否则脚本会继续往下执行后面的命令,最终整个脚本的退出码是最后一个执行命令的退出码。这可能就是你遇到的情况:虽然中间某个call被杀死了,但脚本接着跑完了剩下的命令,如果最后一个命令成功了,脚本就返回0,你的dotnet服务自然捕获不到错误。
那怎么让脚本在某个call失败时立刻退出,并且把错误码传递出去呢?给你两个实用方案:
方案一:手动检查每个命令的退出状态
在每个命令后面加上|| exit $?,这样一旦某个命令失败(不管是主动exit 1还是被信号杀死),脚本会立刻终止,并且返回该命令的退出码:
#!/bin/bash call01 || exit $? call02 || exit $? ... call_N || exit $?
方案二:开启脚本的“errexit”模式
在脚本开头加上set -e(或者等价的set -o errexit),这样只要任何一个命令返回非0的退出码,脚本就会立即终止:
#!/bin/bash set -e call01 call02 ... call_N
不过要注意set -e有几个例外场景:比如在if判断、while循环里的命令失败,不会触发脚本退出;还有管道中的命令失败(如果要覆盖这个例外,可以再加set -o pipefail)。另外,当进程被信号杀死时,它的退出码是128 + 信号编号(比如被SIGKILL(信号9)杀死,退出码就是137),这种非0的状态也会触发set -e让脚本退出。
最后补充下:你测试用exit 1能捕获到,是因为这个命令明确返回了非0码,但如果脚本没设置终止逻辑,只有最后一个命令的退出码会成为脚本的最终退出码。而当命令被OS杀死时,要是脚本没提前终止,后面的命令正常执行完,脚本就会返回0,这就导致你的dotnet服务误以为脚本执行成功了。
备注:内容来源于stack exchange,提问作者Yuri Makassiouk

