62

Using the Pipeline plugin in Jenkins 2.x, how can I access a Groovy variable that is defined somewhere at stage- or node-level from within a sh step?

Simple example:

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
    }
}

gives the following on the Jenkins output page:

[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

As one can see, echo in the sh step prints an empty string.

A work-around would be to define the variable in the environment scope via

env.some_var = 'Hello World'

and print it via

sh 'echo ${env.some_var}'

However, this kind of abuses the environmental scope for this task.

Dirk
  • 9,381
  • 17
  • 70
  • 98
  • 3
    Possible duplicate of [What's the difference of strings within single or double quotes in groovy?](http://stackoverflow.com/questions/6761498/whats-the-difference-of-strings-within-single-or-double-quotes-in-groovy) – Dave Bacher Oct 11 '16 at 17:42
  • 1
    Not exactly a duplicate, but I think it's a simple matter of using the correct quotes. The examples given in the page you linked use double quotes: https://jenkins.io/doc/book/pipeline/overview/#basic-groovy-syntax-for-pipeline-configuration – Dave Bacher Oct 11 '16 at 17:42
  • Indeed, thank you for pointing this out. Should have looked more carefully... when using double quotes, the interpolation works as expected. You might add this as an answer if you like. – Dirk Oct 12 '16 at 08:33
  • 1
    @Dirk Your workaround is actually the correct way to do it safely: https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#injection-via-interpolation – Bruno Mar 13 '23 at 09:26

5 Answers5

84

To use a templatable string, where variables are substituted into a string, use double quotes.

sh "echo $some_var"
Dave Bacher
  • 15,652
  • 3
  • 63
  • 86
  • 12
    For sh env vars we must do sh "echo \$some_var" – Pedro Reis Mar 23 '18 at 17:22
  • 4
    Warning: A secret was passed to "sh" using Groovy String interpolation, which is insecure. Affected argument(s) used the following variable(s): [GIT_PASSWORD, GIT_USERNAME] See https://jenkins.io/redirect/groovy-string-interpolation for details. – coz Dec 17 '20 at 19:58
  • I have been looking into a pipeline script for so long before I managed to fix it... your response was a part of the solution, thank you, sir! :) – Balu Nov 12 '21 at 23:11
  • It helps me. Using double quotes like `sh "echo $file_name"` in groovy passes variable to another shell command. – akshay_sushir Nov 15 '22 at 09:57
  • Please note that this is vulnerable to [injection via interpolation](https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#injection-via-interpolation). The workaround suggested in the question is actually the safe way to achieve this. Double-quotes should generally be avoided unless you absolutely trust the contents of the variable in advance. – Bruno Mar 12 '23 at 20:49
26

I am adding the comment from @Pedro as an answer because I think it is important.

For sh env vars we must use

sh "echo \$some_var" 
hetptis
  • 786
  • 1
  • 12
  • 23
8

You need to do something like below if a bash script is required :

Set this variable at global or local(function) level where from these can be accessible to sh script:

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

In shell script call them like below

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

Make sure you start and end sh with three quotes like '''

Shubham Jain
  • 16,610
  • 15
  • 78
  • 125
  • 1
    This is more or less equivalent to Groovy string interpolation, and can be insecure in the general case. See problem and alternatives in the documentation: https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#injection-via-interpolation – Bruno Mar 13 '23 at 09:32
  • gives error if the variable does not exist in the ELSE block which it is not supposed to execute – avadhut007 Jul 19 '23 at 17:45
3

I would like to add another scenario to this discussion. I was using shell environment variables and groovy variables in the same script.

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

So here, What I have done is use \$ only for shell environment variables and use $ for groovy variables.

BlackViper
  • 53
  • 5
0

This is extension to @Dave Bacher's answer. I'm running multiple shell command in Groovy file & want to use output of one shell command to the next command as groovy variable. Using double quotes in shell command, groovy passes variable from one to another command but using single quotes it does not work, it returns null.

So use shell command like this in double quotes: 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}"
  
akshay_sushir
  • 1,483
  • 11
  • 9
  • When using `sh`, this can be vulnerable to [injection via interpolation](https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#injection-via-interpolation). In your case, `WORKSPACE` is already an environment variable so can be used directly in the shell. If you declare `env.FOLDER_NAME = ...` instead, you can then use single quotes: `sh 'mkdir -p "$WORKSPACE/$FOLDER_NAME" ...` (note: the double quotes belong to bash not the Groovy script, but can be useful if either `WORKSPACE` or `FOLDER_NAME` contain spaces) – Bruno Mar 13 '23 at 09:36