Bash脚本正常执行后二次source执行异常退出登录问题
Bash脚本执行后source触发异常退出的问题分析与解决
问题描述
有一段Bash脚本,预期逻辑是:
- 直接执行(非source方式)时,检测到非source模式,输出提示后以
exit 1退出 - source执行时,正常完成脚本逻辑
但实际出现异常:直接执行脚本触发exit 1后,第二次source执行该脚本时,会错误识别为非source模式,最终导致当前Shell会话直接退出(出现Connection to xxx closed)。仅source执行或把exit 1改为exit时,一切正常。该问题在多版本Bash及不同Linux发行版中均存在。
原脚本代码
#!/bin/bash # testme.sh $(return >/dev/null 2>&1) if [[ $? -ne 0 ]]; then echo status = $? echo Source-execution required. exit 1 else if [[ ${BASH_VERSINFO:-0} -ge 4 ]]; then iam=${BASH_SOURCE##*/} else echo Bash 4 or later required. return fi fi echo done ${iam}
现象复现
# 首次source执行,正常输出 . testme.sh done testme.sh # 直接执行脚本,输出提示后退出 testme.sh status = 0 Source-execution required. # 再次source执行,错误进入非source分支,导致会话退出 . testme.sh status = 0 Source-execution required. Connection to 192.168.2.102 closed.
问题根源
$?引用时机错误:脚本中echo status = $?输出的是if [[ $? -ne 0 ]]这个条件判断的退出状态,而非前面$(return...)的执行状态,导致调试信息完全误导,无法准确判断return的执行结果。- source检测方式不可靠:通过子Shell执行
return来判断是否处于source模式,这种方式会受父Shell的历史退出状态干扰。当直接执行脚本用exit 1退出后,父Shell的$?被设为1,后续source执行时,子Shell的return判断逻辑失效,错误进入直接执行分支,触发exit 1退出当前Shell会话。
修复方案
修复后的脚本
#!/bin/bash # testme.sh # 直接在当前Shell执行return,可靠判断是否为source模式 if ! return >/dev/null 2>&1; then echo "Source-execution required." exit 1 fi # 检查Bash版本 if [[ ${BASH_VERSINFO:-0} -ge 4 ]]; then iam=${BASH_SOURCE##*/} else echo "Bash 4 or later required." return fi echo done ${iam}
修复说明
- 直接在当前Shell执行
return来判断模式:如果是直接执行脚本,return会执行失败(非函数/脚本source场景下不能用return);如果是source执行,return执行成功(重定向输出避免报错信息),以此准确区分两种执行模式。 - 移除了错误的
$?调试输出,避免混淆状态值。
验证结果
- 首次source执行:正常输出
done testme.sh - 直接执行脚本:输出
Source-execution required.后退出 - 直接执行后再次source:正常输出
done testme.sh,不会出现会话退出的问题
内容的提问来源于stack exchange,提问作者Dude
相关产品推荐
相关产品推荐

