Jenkinsfile中Bash脚本无法替换Groovy变量的问题求助
问题:Jenkinsfile中Groovy变量无法在多行shell脚本中读取
在基于Groovy的Jenkinsfile中,尝试将变量build_tag代入shell脚本作为Docker容器名称时,脚本内部始终无法读取该变量值,但脚本前后的语句都能正常输出变量内容。已尝试用双引号包裹${hub_org}/player:${build_tag}、将字符串存入变量后替换等方法,均无效。
相关代码片段
Jenkinsfile核心代码
stage('Snyk Scan') { if (params.buildDockerImage == 'true') { println(ANSI_BOLD + ANSI_GREEN + "build_tag with value as: " + build_tag + ANSI_NORMAL) // 正常输出 sh("echo build tag is ${build_tag}") // 正常输出 sh ''' export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" snyk container test ${hub_org}/player:${build_tag} --json | snyk-to-html -d -o snyk_results.html ''' sh("echo build tag is ${build_tag}") // 正常输出 } }
build_tag定义代码
node('build-slave') { try { String ANSI_GREEN = "\u001B[32m" ... // 其他颜色变量 ansiColor('xterm') { timestamps { stage('Checkout') { if (!env.hub_org) { println(ANSI_BOLD + ANSI_RED + "Uh Oh! Please set a Jenkins environment variable named hub_org with value as registery/sunbidrded" + ANSI_NORMAL) error 'Please resolve the errors and rerun..' } else { println(ANSI_BOLD + ANSI_GREEN + "Found environment variable named hub_org with value as: " + hub_org + ANSI_NORMAL) } } checkout scm commit_hash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() build_tag = sh(script: "echo " + params.github_release_tag.split('/')[-1] + "_" + commit_hash + "_" + env.BUILD_NUMBER, returnStdout: true).trim() echo "build_tag: " + build_tag stage('Customize dependencies') { ... } stage('Snyk Setup') { ... } ...
控制台输出片段
22:54:42 + snyk container test registery/sunbidrded/player: --json 22:54:42 + snyk-to-html -d -o snyk_results.html 22:54:47 Vulnerability snapshot saved at snyk_results.html [Pipeline] sh 22:54:47 + echo build tag is container_scanning_ad2aecee29_23 22:54:47 build tag is container_scanning_ad2aecee29_23
可以看到${build_tag}在shell脚本中被解析为空,容器名称后仅保留冒号。
问题原因
Groovy中,三个单引号(''')包裹的是多行原生字符串,不会对其中的${变量}进行插值解析。因此脚本里的${hub_org}和${build_tag}会被当作shell自身的变量处理,而shell环境中未定义这些变量,最终输出为空。
而之前的sh("echo build tag is ${build_tag}")使用双引号包裹,Groovy会先完成变量插值,再将完整字符串传递给shell执行,所以能正常输出。
解决方法
方法1:改用双引号包裹脚本,转义内部双引号
将shell脚本用三个双引号(""")包裹,同时对脚本内部的双引号用\转义,确保Groovy先完成变量插值,再传递给shell。注意shell自身的变量(如$HOME)要加\避免被Groovy误插值:
sh """ export NVM_DIR=\"\$HOME/.nvm\" [ -s \"\$NVM_DIR/nvm.sh\" ] && . \"\$NVM_DIR/nvm.sh\" [ -s \"\$NVM_DIR/bash_completion\" ] && . \"\$NVM_DIR/bash_completion\" snyk container test ${hub_org}/player:${build_tag} --json | snyk-to-html -d -o snyk_results.html """
方法2:注入Groovy变量到shell环境变量
通过sh命令的environment参数将Groovy变量注入shell环境,脚本中直接使用shell环境变量(推荐,避免转义麻烦):
sh(script: ''' export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" snyk container test $HUB_ORG/player:$BUILD_TAG --json | snyk-to-html -d -o snyk_results.html ''', environment: [ HUB_ORG: hub_org, BUILD_TAG: build_tag ])
方法3:字符串拼接单引号脚本
将需要插值的变量部分用双引号包裹,与单引号脚本拼接,Groovy会自动解析双引号内的变量:
sh ''' export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" snyk container test ''' + "${hub_org}/player:${build_tag}" + ''' --json | snyk-to-html -d -o snyk_results.html '''
内容的提问来源于stack exchange,提问作者godofgeeks
相关产品推荐
相关产品推荐

