如何在Shell脚本if-else块中SSH连接VM?解决语法报错问题
Jenkins Shell脚本if-else块报错及SSH连接解决方案
报错原因排查
出现Syntax error: end of file unexpected (expecting "fi")通常和以下几个问题有关:
- 换行符不兼容:脚本用Windows编辑器编写,换行符是
\r\n,Linux环境下会把\r识别为字符,导致fi语句被截断,Shell无法识别闭合标记。 - SSH命令的语法冲突:if块内的SSH命令如果使用未转义的引号、或者嵌套了与本地Shell语法冲突的符号(比如
{}、$()),会干扰本地Shell对if-else结构的解析,提前终止脚本。 - 语法拼写错误:
fi拼写错误(比如写成FI)、if/else块未正确对齐、或者存在多余的特殊字符(比如不可见的空格)。
正确实现示例
以下是符合要求的完整Shell脚本,包含容器状态判断、镜像推送、SSH远程执行脚本的逻辑:
#!/bin/bash # 定义容器名称和镜像信息 CONTAINER_NAME="app-container" IMAGE_TAG="your-registry/app:latest" REMOTE_VM="deploy-user@192.168.1.100" # 检查容器是否运行 if docker inspect --format '{{.State.Running}}' "$CONTAINER_NAME" | grep -q "true"; then # 容器运行中:推送镜像到仓库 echo "推送镜像 $IMAGE_TAG..." docker push "$IMAGE_TAG" # SSH连接远程VM执行refresh脚本 ssh "$REMOTE_VM" << 'REMOTE_EOF' # 远程服务器上的操作 cd /opt/app-deploy chmod +x refresh.sh ./refresh.sh echo "远程刷新完成" REMOTE_EOF else # 容器未运行:导出日志并清理资源 echo "容器未运行,导出错误日志..." docker logs "$CONTAINER_NAME" > /var/log/jenkins/container-fail.log 2>&1 docker stop "$CONTAINER_NAME" || true docker rm "$CONTAINER_NAME" || true fi
关键注意事项
- 指定Shell解释器:脚本开头必须加
#!/bin/bash,避免Jenkins使用默认的sh(语法限制更多,容易触发兼容性问题)。 - SSH here-doc写法:使用
<< 'REMOTE_EOF'(单引号包裹分界符),这样远程命令中的变量、特殊符号不会被本地Shell解析,避免语法冲突;如果需要传递本地变量到远程,去掉单引号即可,但要注意转义特殊字符。 - 容器状态检查:用
docker inspect配合grep -q做静默判断,避免输出内容干扰脚本逻辑。 - 容错处理:清理资源时加
|| true,防止容器已经停止/删除时命令失败,导致脚本终止。
报错修复步骤
- 转换换行符:如果脚本是Windows环境编写的,用
dos2unix转换为Linux格式:dos2unix your-jenkins-script.sh - 验证语法:在本地执行
bash -n your-jenkins-script.sh,检查脚本语法是否有错误,提前定位问题。 - 检查引号嵌套:如果远程命令需要使用引号,用转义符处理,比如远程命令中的单引号写成
'\'',或者改用双引号包裹远程命令块(注意变量解析的差异)。 - 替换分界符:如果脚本中存在多个here-doc,避免使用相同的分界符(比如都用
EOF),改用不同的名称(比如REMOTE_EOF、LOCAL_EOF),防止提前结束代码块。
内容的提问来源于stack exchange,提问作者James Taylor
相关产品推荐
相关产品推荐

