5

The answers to this question were inspired by @codeGeass' comment to an answer to How to execute a command in a Jenkins 2.0 Pipeline job and then return the stdout:

Can we use them together ? catch returnStdout in a variable and returnStatus in an other ? because it is not cool to repeat the sh script twice

Gerold Broser
  • 14,080
  • 5
  • 48
  • 107
  • A [solution was provided](https://stackoverflow.com/a/32129323/598141) to a similar question, but just for shell cmd, outside of Jenkins. – Ian W Aug 29 '21 at 00:04
  • @IanW Thanks for the info. I think that the OP's demand "_Filter stderr_" there complicates things...and...as you say, it's without Jenkins. – Gerold Broser Aug 29 '21 at 23:35
  • Nope. Should I? – Ian W Sep 19 '21 at 10:33
  • 2
    I stopped wondering why some Q get downvotedd and closed almost instantly, while others which clearly should be downvoted and closed or just deleted (the homework type, no research, helpdesk, etc.) never seems to be. Maybe change wording to not say self-answered, instead, in an extension to this Q, added scenario ... – Ian W Sep 19 '21 at 10:59

2 Answers2

6

To return stdout and stderr together with the status you can do the following:

def runScript(command) {
    script {
        sh script: "set +x ; $command 2>&1 && echo \"status:\$?\" || echo \"status:\$?\" ; exit 0", returnStdout: true
    }
}

pipeline {
    agent any

    stages {
        stage('more values from sh') {
            steps {
                script {
                    // inline
                    def stdoutAndStatus = sh script: 'set +x ; ls -a 2>&1 && echo "status:$?" || echo "status:$?" ; exit 0', returnStdout: true
                    echo "stdoutAndStatus: >$stdoutAndStatus<".trim()
                    
                    def stderrAndStatus = sh script: 'set +x ; ls notexisting 2>&1 && echo "status:$?" || echo "status:$?" ; exit 0', returnStdout: true
                    echo "stderrAndStatus: >$stderrAndStatus<".trim()
                    
                    // with function
                    echo "runScript: >${runScript('ls -a')}<".trim()
                    echo "runScript: >${runScript('ls notexisting')}<".trim()
                    
                    // failing the sh step
                    echo "runScript: >${runScript('not_existing_command')}<".trim()
                }
            }
        }
    }
}

Console Output

[Pipeline] stage
[Pipeline] { (more values from sh)
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ set +x
[Pipeline] echo
stdoutAndStatus: >.
..
status:0
<
[Pipeline] sh
+ set +x
[Pipeline] echo
stderrAndStatus: >ls: notexisting: No such file or directory
status:2
<
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ set +x
[Pipeline] }
[Pipeline] // script
[Pipeline] echo
runScript: >.
..
status:0
<
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ set +x
[Pipeline] }
[Pipeline] // script
[Pipeline] echo
runScript: >ls: notexisting: No such file or directory
status:2
<
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ set +x
[Pipeline] }
[Pipeline] // script
[Pipeline] echo
runScript: >C:/Users/jenkins/AppData/Local/Jenkins/.jenkins/workspace/SO-36956977 more values from sh@tmp/durable-af2cee22/script.sh: line 1: not_existing_command: command not found
status:127
<
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Gerold Broser
  • 14,080
  • 5
  • 48
  • 107
  • Thanks for the solution! However the shell script step doesn't display the whole CLI command, but only the first part: `+ set +x`. Do you know if there is a way to fix it? – Boris Oct 05 '22 at 20:30
  • 1
    @Boris See [Bash's `set`](https://ss64.com/bash/set.html): "_Using + rather than - will cause the option to be turned off._". – Gerold Broser Oct 06 '22 at 11:04
1

In plain (Windows Git) Bash it works as follows (inspired by @Ian W's comment to the question above):

stdErrAndOutAndStatus.sh

stdErrAndOutAndStatus () {
    $1 2>&1 ; echo "status:$?"
}

stdOutAndStatus=$( stdErrAndOutAndStatus 'ls -a' )
echo -e "$stdOutAndStatus\n"
stdErrAndStatus=$( stdErrAndOutAndStatus 'ls notexisting' )
echo -e "$stdErrAndStatus\n"
stdErrAndStatus=$( stdErrAndOutAndStatus 'not_existing_command' )
echo -e "$stdErrAndStatus\n"

Output

$ ./stdErrAndOutAndStatus.sh
.
..
stdErrAndOutAndStatus.sh
status:0

ls: cannot access 'notexisting': No such file or directory
status:2

./stdErrAndOutAndStatus.sh: line 3: not_existing_command: command not found
status:127

NB: I hope there's no pitfall of/in Bash I'm not aware of (yet). I don't write scripts too often.

Gerold Broser
  • 14,080
  • 5
  • 48
  • 107