迁移至SLES 12后调用rc.status的Bash脚本执行两次问题
这个问题我太熟了!之前帮团队迁移SLES版本时刚好碰到过一模一样的情况,核心原因就是SLES 12对/etc/rc.status做了逻辑改动,咱们一步步拆解:
问题复现
你给出的最简测试脚本test.sh完美复现了问题:
#!/bin/bash echo Sourcing rc.status . /etc/rc.status echo End of script
当执行./test.sh status时,输出如下:
Sourcing rc.status
Sourcing rc.status
End of script
根因分析
在SLES 11中,/etc/rc.status只是个单纯的函数库,负责定义状态检查、输出相关的工具函数,不会主动触发脚本重执行。但到了SLES 12,这个脚本加入了自动处理status参数的逻辑:当它检测到当前脚本是通过status参数启动时,会重新调用整个脚本(相当于帮你再跑一遍./test.sh status),这就导致了脚本内容被执行两次的假象。
解决方案
根据你的脚本需求,有几种不同的解决方式:
方案1:临时屏蔽rc.status的自动重调逻辑
如果你的脚本不需要rc.status处理status参数的额外功能,可以在引入它之前临时修改脚本参数,避免触发重调:
#!/bin/bash echo Sourcing rc.status # 临时保存原参数,替换为非status的占位参数 ORIG_ARGS="$@" set -- dummy . /etc/rc.status # 恢复原脚本参数 set -- $ORIG_ARGS echo End of script
方案2:区分首次执行与rc.status触发的执行
SLES 12的rc.status在触发重执行时,会设置一个RC_STATUS_INVOKED环境变量,我们可以通过这个变量判断是否是重复执行,从而跳过不需要重复的代码:
#!/bin/bash # 仅在首次执行时打印这条信息 if [ -z "$RC_STATUS_INVOKED" ]; then echo Sourcing rc.status fi . /etc/rc.status echo End of script
这样运行时只会看到一次Sourcing rc.status输出,解决重复问题。
方案3:遵循SLES 12规范重构脚本
如果你的脚本是系统服务类的管理脚本,最规范的做法是按照SLES 12的init脚本标准,把核心逻辑拆分为对应函数,让rc.status调用指定函数而非整个脚本:
#!/bin/bash # 先引入rc.status . /etc/rc.status # 自定义status逻辑,rc.status会自动调用这个函数 status() { echo "执行自定义状态检查逻辑..." # 调用rc.status的标准状态输出函数 rc_status -v } # 处理脚本参数 case "$1" in status) status ;; *) echo "Usage: $0 status" exit 1 ;; esac # 输出最终状态 rc_status
这种方式完全贴合SLES 12的系统规范,从根源上避免了重复执行的问题,也更易于维护。
内容的提问来源于stack exchange,提问作者zb226

