在Jenkins管道中的shell步骤中访问Groovy变量

65
使用Jenkins 2.x中的Pipeline插件,如何从sh步骤内部访问在阶段或节点级别定义的Groovy变量?
简单示例:
node {
    stage('Test Stage') {
        some_var = 'Hello World' // this is Groovy
        echo some_var // printing via Groovy works
        sh 'echo $some_var' // printing in shell does not work
    }
}

在Jenkins输出页面上会显示以下内容:
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test Stage)
[Pipeline] echo
Hello World
[Pipeline] sh
[test] Running shell script
+ echo

[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

正如人们所看到的,在sh步骤中,echo输出了一个空字符串。

一种解决方法是通过在环境范围内定义变量来实现。

env.some_var = 'Hello World'

通过打印输出它

sh 'echo ${env.some_var}'

然而,这种做法滥用了该任务的环境范围。

1
虽然不完全相同,但我认为这只是使用正确引号的简单问题。您链接的页面中给出的示例使用双引号:https://jenkins.io/doc/book/pipeline/overview/#basic-groovy-syntax-for-pipeline-configuration - Dave Bacher
的确,感谢您指出这一点。我应该更仔细地查看... 当使用双引号时,内插将按预期工作。如果您愿意,请将此添加为答案。 - Dirk
1
@Dirk,你的解决方法实际上是安全地执行它的正确方式:https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#injection-via-interpolation - Bruno
5个回答

87

为了使用可模板化的字符串,其中变量被替换为字符串,请使用双引号。

sh "echo $some_var"

12
对于sh环境变量,我们必须执行sh "echo $some_var"。 - Pedro Reis
4
警告:使用 Groovy 字符串插值将一个秘密传递给“sh”,这是不安全的。 受影响的参数使用了以下变量:[GIT_PASSWORD, GIT_USERNAME] 请参考 https://jenkins.io/redirect/groovy-string-interpolation 获取详细信息。 - coz
我在研究管道脚本很长时间后才成功修复它...您的回复是解决方案的一部分,谢谢您,先生! :) - Balu
它对我很有帮助。在Groovy中使用双引号,例如sh "echo $file_name",可以将变量传递给另一个shell命令。 - akshay_sushir
请注意,这种方法容易受到插值注入攻击。问题中建议的解决方法实际上是安全的。除非您事先绝对信任变量的内容,否则应该避免使用双引号。 - Bruno

26

我将@Pedro的评论作为回答添加,因为我认为它很重要。

对于sh环境变量,我们必须使用

sh "echo \$some_var" 

或者简单地说:sh 'echo $some_var' - Tristan
这个解决方案对我没有用,只有@dave-bacher发布的那一个有效。 - Balu

8

如果需要一个bash脚本,您需要执行以下类似的操作:

在全局或本地(函数)级别上设置此变量,以便可以从sh脚本中访问它们:

def stageOneWorkSpace = "/path/test1"
def stageTwoWorkSpace = "/path/test2"

在shell脚本中,可以像下面这样调用它们:

sh '''
echo ''' +stageOneWorkSpace+ '''
echo ''' +stageTwoWorkSpace+ '''
cp -r ''' +stageOneWorkSpace+'''/qa/folder1/* ''' +stageOneWorkSpace+'''/qa/folder2
'''

请确保你在sh脚本的开头和结尾都使用三个引号,例如'''


1
这与Groovy字符串插值更或多或少相当,并且在一般情况下可能存在不安全性。请参阅文档中的问题和替代方法:https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#injection-via-interpolation - Bruno
如果变量在不应执行的ELSE块中不存在,则会出现错误。 - avadhut007

3

我想在此讨论中添加另一种情况。 我在同一个脚本中使用了shell环境变量和groovy变量。

 format='html'
    for file in *.txt; 
        do mv  -- "\$file" "\${file%.txt}.$format";
    done

所以这里,我所做的是仅在shell环境变量中使用 $,而在groovy变量中使用 \$。


0
这是对@Dave Bacher答案的扩展。我在Groovy文件中运行多个shell命令,想要将一个shell命令的输出作为groovy变量传递给下一个命令。在shell命令中使用双引号,groovy可以将变量从一个命令传递到另一个命令,但是使用单引号不起作用,它会返回null。
因此,在双引号中使用以下shell命令: sh "echo ${FOLDER_NAME}"
FOLDER_NAME = sh(script: $/
    awk -F '=' '/CODE_COVERAGE_FOLDER/ {gsub("\"","");print$2}' ${WORKSPACE}/test.cfg
  /$, returnStdout: true).trim()

echo "Folder: ${FOLDER_NAME}" // print folder name in groovy console

sh "mkdir -p ${WORKSPACE}/${FOLDER_NAME} && chmod 777 ${WORKSPACE}/${FOLDER_NAME}"
  

当使用 sh 时,这可能会容易受到 插值注入 的攻击。在您的情况下,WORKSPACE 已经是环境变量,因此可以直接在 shell 中使用它。如果您声明 env.FOLDER_NAME = ...,则可以使用单引号:sh 'mkdir -p "$WORKSPACE/$FOLDER_NAME" ...(注意:双引号属于 bash 而不是 Groovy 脚本,但如果 WORKSPACEFOLDER_NAME 包含空格,则可能很有用)。 - Bruno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接