<p>There is a simple solution for declarative pipeline which doesn't involve having to write to files - define the variable-to-be-shared <em>outside</em> the <code>pipeline</code> block. This is much neater and means you should still be able to restart the job from the later stage if you need.</p>
<p>Example:</p>
<pre><code>def variable = &quot;initial value&quot;
pipeline {
    agent {
        ...
    }
    stages {
        stage(&quot;Override variable&quot;) {
            steps {
                script {
                    variable = sh(script: 'some command', returnStdout: true).trim()
                }
            }
        }
        stage(&quot;Read new value of variable&quot;) {
            steps {
                script {
                    echo variable
                }
            }
        }
    }
}
</code></pre>
<p>Further explanation in <a href="https://www.youtube.com/watch?v=41uUsWQjKRw" rel="nofollow noreferrer">video form</a></p>

CC BY-SA 4.0
2023-05-22T10:44:16.110Z
2023-06-16T22:33:00.717Z
2023-06-16T22:33:00.717Z
Dave
<p>For Declarative Pipeline:</p>

<p>This question already has a <a href="https://stackoverflow.com/a/44101004/1824868">highly-upvoted answer on StackOverflow</a>:</p>

<blockquote>
  <p>If you want to use a file (since a script is the thing generating the value you need):</p>

<pre><code>pipeline {
  agent { label 'docker' }
  stages {
    stage('one') {
      steps {
        sh 'echo hotness &gt; myfile.txt'
        script {
          // trim removes leading and trailing whitespace from the string
          myVar = readFile('myfile.txt').trim()
        }
        echo "${myVar}" // prints 'hotness'
      }
    }
    stage('two') {
      steps {
        echo "${myVar}" // prints 'hotness'
      }
    }
    // this stage is skipped due to the when expression, so nothing is printed
    stage('three') {
      when {
        expression { myVar != 'hotness' }
      }
      steps {
        echo "three: ${myVar}"
      }
    }
  }
}
</code></pre>
</blockquote>

<p>A second solution would be to write out output from your script directly or with <a href="https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#writefile-write-file-to-workspace" rel="noreferrer"><code>writeFile</code></a> and then later read it back in with <a href="https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#readfile-read-file-from-workspace" rel="noreferrer"><code>readFile</code></a>.  However, this comes with the significant caveat that both the reading and writing must take place on the same node, so you can't use this to send data across nodes.</p>

<p>You can also can archive files centrally with <a href="https://jenkins.io/doc/pipeline/steps/core/#archiveartifacts-archive-the-artifacts" rel="noreferrer"><code>archiveArtifact</code></a> and retrieve them with <a href="https://jenkins.io/doc/pipeline/steps/copyartifact/#copyartifacts-copy-artifacts-from-another-project" rel="noreferrer"><code>copyArtifact</code></a> (and then read in the file with <code>readFile</code>).</p>

<p>Finally, there are some answers to a <a href="https://stackoverflow.com/q/47462500/1824868">near-identical question on StackOverflow</a> that offer alternative solutions.</p>

<hr>

<p>However, if you can, I would suggest using Scripted Pipeline instead, which allows a much simpler solution:</p>

<pre><code>def String myVar

stage('my-first-stage') {
  myVar = sh(script: 'my-command', returnStdout: true)
}

stage('my-second-stage') {
  sh("my-other-command --var='${myVar}'")
}
</code></pre>

<p>(I also already answered this question for Scripted Pipeline over on <a href="https://serverfault.com/a/884798/213070">ServerFault</a>.)</p>

<hr>

<p>It looks like some of these solutions have already been proposed in the comments, but you are concerned that they are not elegant enough.  I'm not really sure what kind of elegance you're looking for, because I can't think of any way to simplify these answers in Jenkins-Pipeline-land.</p>

CC BY-SA 4.0
2018-10-23T23:18:08.300Z
2018-11-26T04:24:55.493Z
2018-11-26T04:24:55.493Z
jayhendren
<p>I have a declarative Jenkins pipeline that looks like the following:</p>

<pre><code>pipeline{
    agent {
        ...
    }
    stages {
        stage("Provision EC2 Instance and Set ENV Variable"){
            steps {
                dir("docker-image-builder"){
                    sh 'python ./provisonInstance.py'
                }
            }
        }
        stage("Configure EC2 Instance with Ansible"){
            steps {
                ansiblePlaybook('./ansible.playbook.yml') {
                    ansibleName('1.9.4')
                }
            }
        }
    }
}
</code></pre>

<p>In my first stage, I have a Python script that provisions an <a href="http://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud" rel="noreferrer">Amazon EC2</a> instance that will be used to create an <a href="https://en.wikipedia.org/wiki/Amazon_Machine_Image" rel="noreferrer">AMI</a>. In the second stage, I will then configure configure my instance before finally creating an AMI and terminating the instance. In order to do this, I need the instance-id of the EC2 instance created in the first stage. <strong>Is there an elegant way to pass values generated by a script between stages, and if so how?</strong></p>

<p>The most obvious method that I can think of is to write the value to a file on the agent in the first stage, and read it in the second stage, but this does not seem like an elegant solution.</p>

CC BY-SA 4.0
2018-10-18T15:08:58.790Z
Not a full answer as we use scripted, not declarative pipelines, but writing to a file is exactly what I ended up doing in our scripts.
Alex
CC BY-SA 4.0
2018-10-19T13:36:33.033Z
This question has been answered here https://stackoverflow.com/questions/47155326/reuse-object-property-in-different-stages-of-a-declerative-pipeline-in-jenkins/47158534#47158534
Ram
CC BY-SA 4.0
2018-10-19T14:12:01.970Z
@RamKamath The answer to that question is a little different. I am trying to take output from a python script and pass it to a stage. While I think that part of the answer is to create a global environment variable, set it in the first stage, and read it in the second stage, it doesn't provide an elegant way to pass it from the python script at the stage level.
Preston Martin
<jenkins><ansible><jenkins-pipeline><python>
Passing variables between scripts in a Jenkins pipeline
Preston Martin
# Passing variables between scripts in a Jenkins pipeline

(Asked by: username_0 on 2018-10-17)

I have a declarative Jenkins pipeline that looks like the following:
pipeline{
    agent {
        ...
    }
    stages {
        stage("Provision EC2 Instance and Set ENV Variable"){
            steps {
                dir("docker-image-builder"){
                    sh 'python ./provisonInstance.py'
                }
            }
        }
        stage("Configure EC2 Instance with Ansible"){
            steps {
                ansiblePlaybook('./ansible.playbook.yml') {
                    ansibleName('1.9.4')
                }
            }
        }
    }
}

In my first stage, I have a Python script that provisions an Amazon EC2 instance that will be used to create an AMI. In the second stage, I will then configure configure my instance before finally creating an AMI and terminating the instance. In order to do this, I need the instance-id of the EC2 instance created in the first stage. Is there an elegant way to pass values generated by a script between stages, and if so how?
The most obvious method that I can think of is to write the value to a file on the agent in the first stage, and read it in the second stage, but this does not seem like an elegant solution.

**Tags:** jenkins, ansible, jenkins-pipeline, python

> **Comments:**
> **username_1**: Not a full answer as we use scripted, not declarative pipelines, but writing to a file is exactly what I ended up doing in our scripts.  
> **username_2**: This question has been answered here https://stackoverflow.com/questions/47155326/reuse-object-property-in-different-stages-of-a-declerative-pipeline-in-jenkins/47158534#47158534  
> **username_0**: @username_2Kamath The answer to that question is a little different. I am trying to take output from a python script and pass it to a stage. While I think that part of the answer is to create a global environment variable, set it in the first stage, and read it in the second stage, it doesn't provide an elegant way to pass it from the python script at the stage level.  

---

## 2 answers

### Answer by username_4 on 2018-10-23. Score: 9 | Accepted answer

For Declarative Pipeline:
This question already has a highly-upvoted answer on StackOverflow:

If you want to use a file (since a script is the thing generating the value you need):
pipeline {
  agent { label 'docker' }
  stages {
    stage('one') {
      steps {
        sh 'echo hotness > myfile.txt'
        script {
          // trim removes leading and trailing whitespace from the string
          myVar = readFile('myfile.txt').trim()
        }
        echo "${myVar}" // prints 'hotness'
      }
    }
    stage('two') {
      steps {
        echo "${myVar}" // prints 'hotness'
      }
    }
    // this stage is skipped due to the when expression, so nothing is printed
    stage('three') {
      when {
        expression { myVar != 'hotness' }
      }
      steps {
        echo "three: ${myVar}"
      }
    }
  }
}


A second solution would be to write out output from your script directly or with writeFile and then later read it back in with readFile.  However, this comes with the significant caveat that both the reading and writing must take place on the same node, so you can't use this to send data across nodes.
You can also can archive files centrally with archiveArtifact and retrieve them with copyArtifact (and then read in the file with readFile).
Finally, there are some answers to a near-identical question on StackOverflow that offer alternative solutions.

However, if you can, I would suggest using Scripted Pipeline instead, which allows a much simpler solution:
def String myVar

stage('my-first-stage') {
  myVar = sh(script: 'my-command', returnStdout: true)
}

stage('my-second-stage') {
  sh("my-other-command --var='${myVar}'")
}

(I also already answered this question for Scripted Pipeline over on ServerFault.)

It looks like some of these solutions have already been proposed in the comments, but you are concerned that they are not elegant enough.  I'm not really sure what kind of elegance you're looking for, because I can't think of any way to simplify these answers in Jenkins-Pipeline-land.


---

### Answer by username_3 on 2023-05-22. Score: 2

There is a simple solution for declarative pipeline which doesn't involve having to write to files - define the variable-to-be-shared outside the pipeline block. This is much neater and means you should still be able to restart the job from the later stage if you need.
Example:
def variable = "initial value"
pipeline {
    agent {
        ...
    }
    stages {
        stage("Override variable") {
            steps {
                script {
                    variable = sh(script: 'some command', returnStdout: true).trim()
                }
            }
        }
        stage("Read new value of variable") {
            steps {
                script {
                    echo variable
                }
            }
        }
    }
}

Further explanation in video form


---

