Jenkins流水线中docker exec命令变量无法展开问题求助
问题原因分析
从Jenkins日志能直接定位问题核心:
docker exec仅执行了容器内的JAVA_VERSION=11.0.21赋值操作,后续的BUILD_METADATA定义、JSON生成步骤,都是在Jenkins宿主机的shell环境里执行的,而非目标容器内部。- 容器内的
JAVA_VERSION是容器进程的局部变量,宿主机shell完全无法读取这个变量,因此宿主机环境中的$JAVA_VERSION为空,最终生成的JSON版本字段自然是空值。
本质原因是命令中的分号;被Jenkins的shell解析成了宿主shell的命令分隔符,把原本要在容器内执行的整条逻辑拆成了宿主环境的多个独立命令。
解决方案
提供两种简洁的修复方式:
方式1:将所有逻辑放入容器内执行,直接输出JSON到宿主机文件
把版本获取、JSON生成的全部逻辑都放到容器内部完成,通过重定向将容器内的输出写入宿主机的目标文件:
sh """ docker exec -i $CONTAINER_NAME bash -c ' JAVA_VERSION=\$(java --version | head -n1 | awk "{print \$2}") echo "{\"environment\": {\"language\": {\"java\": {\"version\":\"\"\$JAVA_VERSION\"\"}}}" ' > ${WORKSPACE}/build_metadata.json """
用三重引号"""包裹Jenkins的sh命令,容器内的bash逻辑用单引号'包裹,避免Jenkins提前解析变量,确保整条逻辑在容器内完整执行。
方式2:分步操作,先获取版本再生成JSON
拆分步骤更清晰,也便于调试:
// 第一步:捕获容器内的Java版本输出 def javaVersion = sh( script: "docker exec -i $CONTAINER_NAME java --version | head -n1 | awk '{print \$2}'", returnStdout: true ).trim() // 第二步:在Jenkins环境中生成JSON文件 sh """ echo '{\"environment\": {\"language\": {\"java\": {\"version\":\"${javaVersion}\"}}}' > ${WORKSPACE}/build_metadata.json """
通过returnStdout: true直接获取容器内Java版本的输出内容,再在Jenkins环境中拼接生成JSON,彻底避免跨环境变量传递的问题。
内容的提问来源于stack exchange,提问作者Johnny Donalistic
相关产品推荐
相关产品推荐

