如何从Jenkinsfile(groovy)中获取使用执行的Shell命令的输出?


213

我在Jenkinsfile(Groovy)上有类似的内容,我想将stdout和退出代码记录在一个变量中,以便以后使用该信息。

sh "ls -l"

我该怎么做,尤其是似乎您无法真正在中运行任何常规代码Jenkinsfile



Answers:


390

最新版本的管道sh步骤允许您执行以下操作;

// Git committer email
GIT_COMMIT_EMAIL = sh (
    script: 'git --no-pager show -s --format=\'%ae\'',
    returnStdout: true
).trim()
echo "Git committer email: ${GIT_COMMIT_EMAIL}"

returnStatus选项是另一个功能。

// Test commit message for flags
BUILD_FULL = sh (
    script: "git log -1 --pretty=%B | grep '\\[jenkins-full]'",
    returnStatus: true
) == 0
echo "Build full flag: ${BUILD_FULL}"

根据问题添加了这些选项。

请参见官方文档sh命令。



但是对我来说,使用“ vars”前缀不起作用。当我只使用GIT_COMMIT_EMAIL作为不带前缀的var name时,一切都很好。
巴斯蒂安·福伊特


7
当我使用声明性jenkinsfile语法时,此方法不起作用,错误消息为:WorkflowScript: 97: Expected a step @ line 97, column 17.
扳手

17
看来这仅在script步骤块内有效。jenkins.io/doc/book/pipeline/syntax/#declarative-steps
黄铜猴


40

快速答案是这样的:

sh "ls -l > commandResult"
result = readFile('commandResult').trim()

我认为有一个功能请求可以获取sh步骤的结果,但据我所知,目前没有其他选择。

编辑:JENKINS-26133

EDIT2:不太确定从什么版本开始,但是sh / bat步骤现在可以返回std输出,只需:

def output = sh returnStdout: true, script: 'ls -l'

1
仅供参考,bat步骤会回显正在运行的命令,因此您需要使用@启动bat命令以获取输出(例如“ @dir”)。
罗素盖洛普

21

如果要获取标准输出并知道命令是否成功,只需使用returnStdout并将其包装在异常处理程序中即可:

脚本化管道

try {
    // Fails with non-zero exit if dir1 does not exist
    def dir1 = sh(script:'ls -la dir1', returnStdout:true).trim()
} catch (Exception ex) {
    println("Unable to read dir1: ${ex}")
}

输出

[Pipeline] sh
[Test-Pipeline] Running shell script
+ ls -la dir1
ls: cannot access dir1: No such file or directory
[Pipeline] echo
unable to read dir1: hudson.AbortException: script returned exit code 2

不幸的是hudson.AbortException缺少获取该退出状态的任何有用方法,因此,如果需要实际值,则需要从消息中解析出它(哎呀!)。

与Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.html相反,捕获到此异常时构建不会失败。如果没有抓住,它将失败!

更新: 如果您还希望从shell命令输出STDERR,那么不幸的是,詹金斯未能正确支持该通用用例。一张2017年的JENKINS-44930票被卡在有意识的乒乓球状态中,但未取得解决方案的任何进展-请考虑添加您的支持票。

至于现在的解决方案,可能有两种可能的方法:

a)将STDERR重定向到STDOUT- 2>&1 但是由您决定将其从主输出中解析出来,并且如果命令失败,您将不会获得输出-因为您位于异常处理程序中。

b)将STDERR重定向到一个临时文件(您之前准备的名称)2>filename(但请记住,之后要清理该文件)-即。主要代码变为:

def stderrfile = 'stderr.out'
try {
    def dir1 = sh(script:"ls -la dir1 2>${stderrfile}", returnStdout:true).trim()
} catch (Exception ex) {
    def errmsg = readFile(stderrfile)
    println("Unable to read dir1: ${ex} - ${errmsg}")
}

c)用另一种方法,returnStatus=true改为设置,省去异常处理程序,并始终将输出捕获到文件中,即:

def outfile = 'stdout.out'
def status = sh(script:"ls -la dir1 >${outfile} 2>&1", returnStatus:true)
def output = readFile(outfile).trim()
if (status == 0) {
    // output is directory listing from stdout
} else {
    // output is error message from stderr
}

注意:上面的代码特定于Unix / Linux-Windows需要完全不同的shell命令。


1
是否有机会获得如下输出:“ ls:无法访问dir1:没有这样的文件或目录”,而不仅仅是“ hudson.AbortException:脚本返回了退出代码2”?
user2988257 '18

我不知道这怎么可能。在我的测试中,从未分配输出文本,这是可以预期的。从shell步骤引发的异常阻止分配返回值
Jakub Bochenski

2
不幸的是,returnStatus和returnStdout不能同时工作。这是票。请投票:issue.jenkins-ci.org/browse/JENKINS-44930
亚历山大·萨莫洛夫

1
@AlexanderSamoylov您必须使用上面的选项(c)中的文件来解决。不幸的是,这些工具的作者经常抱有自以为是的态度,对于其他常见用例并没有提前考虑,这里的“ sh”就是一个很好的例子。
艾德·兰德尔

1
@Ed Randall,完全同意您的意见。这就是为什么我发布此问题,希望由于投票数增加而开始这样做的原因。
亚历山大·萨莫伊洛夫

12

这是一个示例案例,我相信这很有道理!

node('master'){
    stage('stage1'){
    def commit = sh (returnStdout: true, script: '''echo hi
    echo bye | grep -o "e"
    date
    echo lol''').split()


    echo "${commit[-1]} "

    }
}

我不知道方法,但是您的回答对我
很有帮助

5

对于那些需要在后续shell命令中使用输出而不是常规操作的人,可以执行以下示例:

    stage('Show Files') {
        environment {
          MY_FILES = sh(script: 'cd mydir && ls -l', returnStdout: true)
        }
        steps {
          sh '''
            echo "$MY_FILES"
          '''
        }
    }

我发现代码maven上的示例非常有用。


-6

最简单的方法是使用这种方法

my_var=`echo 2` echo $my_var 输出:2

注意,并非简单的单引号是反引号(`)。


赞成,但我建议您展示这些内容,sh否则他们可能会觉得这很古怪,特别是如果他们对bash脚本不熟悉的话。我刚刚在Jenkins上尝试过,使用ls -l代替,echo 2并且可以正常工作。我以前实际上曾使用过这种方法,但是一直在寻找替代方法,因为它不是很可靠。我以这种方式在标准shell上捕获了更复杂的命令的输出,但是sh由于某些未知的原因,当将该变量移植到Jenkins时,它什么也不容纳。
Nagev
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.