启动时Shell脚本EOF内容被跳过:原因分析及修复方案
问题原因分析与修复方案
问题背景
我在/etc/init.d目录中添加了一段用于修改文件内容的Shell脚本:
#!/bin/bash set -x DBMS_ID='testuser' DBMS_PW1='*****' CONFIG_EXEC="./some_program" ${CONFIG_EXEC} config <<EOF yes 127.0.0.1 ${DBMS_ID} ${DBMS_PW1} yes EOF cp -f A.txt B.txt
原本预期的执行结果:
DB configuration... HOST : 127.0.0.1 USER : testuser PASS : ******** PORT : 3306 DB : mysql UNIX_SOCKET : /tmp/mysql.sock TESTING CONFIGURATION ... [ERROR] - Mysql connect error[1045] : Access denied for user 'testuser'@'127.0.0.1' (using password: YES) Do you want to setup database. [yes/no] : HOST : USER : PASS : PORT (Default: 3306) : DB (Default: mysql) : UNIX_SOCKET (Default: /var/lib/mysql/mysql.sock) : TESTING CONFIGURATION ... [OK] Done. + cp -f A.txt B.txt
但重启后出现异常,实际执行结果:
DB configuration... HOST : 127.0.0.1 USER : testuser PASS : ******** PORT : 3306 DB : mysql UNIX_SOCKET : /var/lib/mysql/mysql.sock TESTING CONFIGURATION ... [OK] Do you want to setup database. [yes/no] : HOST : USER : + cp -f A.txt B.txt
可见EOF块中的部分内容被跳过,以下是问题原因与修复方案:
问题原因
- 执行流程不匹配:重启后数据库权限状态变化,
some_program第一次配置测试直接成功(输出[OK]),程序提前结束流程,不再等待后续输入,因此here-document中剩余的两个空行和yes没有被程序读取。 - 调试输出干扰:
set -x的调试输出会写入标准错误,与程序的最后输出(Do you want to setup database...)混合,造成“输入被跳过”的视觉错觉。 - 非终端环境影响:init.d脚本的执行环境中,标准输入并非终端,交互式程序的行为与终端环境下不一致,加剧了输入输出的混乱。
修复方案
方案1:移除或隔离set -x的输出
set -x的调试输出会干扰程序的输入输出流,建议仅在调试时使用,或者将其输出重定向到日志文件:
# 替换原set -x为日志重定向 set -x >> /var/log/init_script_debug.log 2>&1
或者直接移除set -x语句。
方案2:使用动态交互工具(expect)替代here-document
here-document是静态输入,无法根据程序的实时输出调整输入。使用expect可以动态响应程序提示,适配不同执行流程:
#!/bin/bash DBMS_ID='testuser' DBMS_PW1='*****' expect << EOF spawn ./some_program config expect "Do you want to setup database.*" send "yes\r" expect "HOST :" send "127.0.0.1\r" expect "USER :" send "${DBMS_ID}\r" expect "PASS :" send "${DBMS_PW1}\r" expect { "TESTING CONFIGURATION ... *\[ERROR\]" { expect "Do you want to setup database.*" send "yes\r" # 发送空行接受默认配置 send "\r\r\r" expect "TESTING CONFIGURATION ... *\[OK\]" } "TESTING CONFIGURATION ... *\[OK\]" { # 配置直接成功,无需后续输入 } } expect "Done." EOF cp -f A.txt B.txt
(注:需确保系统已安装expect工具,可通过apt install expect或yum install expect安装)
方案3:预检查数据库连接状态,动态调整输入
在执行some_program前,先测试数据库连接,根据结果决定发送的输入内容:
#!/bin/bash DBMS_ID='testuser' DBMS_PW1='*****' # 测试数据库连接 mysql -h127.0.0.1 -u${DBMS_ID} -p${DBMS_PW1} -e "SELECT 1" > /dev/null 2>&1 if [ $? -eq 0 ]; then # 连接成功,发送基础配置 INPUT_CONTENT="yes 127.0.0.1 ${DBMS_ID} ${DBMS_PW1} " else # 连接失败,发送完整流程输入 INPUT_CONTENT="yes 127.0.0.1 ${DBMS_ID} ${DBMS_PW1} yes " fi ./some_program config << EOF ${INPUT_CONTENT} EOF cp -f A.txt B.txt
内容的提问来源于stack exchange,提问作者DannyPoet
相关产品推荐
相关产品推荐

