308

我在 Jenkinsfile (Groovy) 上有类似的东西,我想将标准输出和退出代码记录在一个变量中,以便以后使用这些信息。

sh "ls -l"

我该如何做到这一点,特别是因为您似乎无法真正在Jenkinsfile?

4

10 回答 10

539

最新版本的管道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

对于声明性管道(请参阅注释),您需要将代码包装到script步骤中:

script {
   GIT_COMMIT_EMAIL = sh (
        script: 'git --no-pager show -s --format=\'%ae\'',
        returnStdout: true
    ).trim()
    echo "Git committer email: ${GIT_COMMIT_EMAIL}"
}
于 2016-08-05T07:32:35.890 回答
76

当前的 Pipeline 版本原生支持returnStdoutand returnStatus,这使得从sh/bat步骤获取输出或状态成为可能。

一个例子:

def ret = sh(script: 'uname', returnStdout: true)
println ret

一个官方文档

于 2016-10-12T20:30:31.617 回答
46

快速回答是这样的:

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

我认为存在能够获得 sh 步骤结果的功能请求,但据我所知,目前没有其他选择。

编辑:詹金斯-26133

EDIT2:不太确定从什么版本开始,但 sh/bat 步骤现在可以返回标准输出,简单地说:

def output = sh returnStdout: true, script: 'ls -l'
于 2016-04-11T13:41:04.403 回答
36

如果您想获取标准输出并知道命令是否成功,只需使用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 输出,不幸的是 Jenkins 无法正确支持该常见用例。一张 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 命令。

于 2018-11-12T00:07:33.940 回答
13

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

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


    echo "${commit[-1]} "

    }
}
于 2017-07-20T11:29:21.100 回答
9

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

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

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

于 2019-11-13T15:38:13.663 回答
0

以上所有方法都将起作用。但是要在代码中使用 var 作为 env 变量,您需要先导出 var。

script{
  sh " 'shell command here' > command"
  command_var = readFile('command').trim()
  sh "export command_var=$command_var"
}

用您选择的命令替换 shell 命令。现在,如果您使用的是 python 代码,您只需指定 os.getenv("command_var") 将返回之前执行的 shell 命令的输出。

于 2020-08-26T06:52:31.600 回答
0

如何在 groovy 中读取 shell 变量/如何将 shell 返回值分配给 groovy 变量。

要求:打开一个文本文件,使用 shell 读取行并将值存储在 groovy 中并获取每行的参数。

这里,是分隔符

例如:releaseModule.txt

./APP_TSBASE/app/team/i-home/deployments/ip-cc.war/cs_workflowReport.jar,configurable-wf-report,94,23crb1,artifact



./APP_TSBASE/app/team/i-home/deployments/ip.war/cs_workflowReport.jar,configurable-temppweb-report,394,rvu3crb1,artifact

=========================

这里要获取模块名称第二个参数(configurable-wf-report),构建没有第三个参数(94),commit id 4th(23crb1)

def  module = sh(script: """awk -F',' '{ print \$2 "," \$3 "," \$4 }' releaseModules.txt  | sort -u """, returnStdout: true).trim()

echo module

List lines = module.split( '\n' ).findAll { !it.startsWith( ',' ) }

def buildid

def Modname

lines.each {

List det1 =  it.split(',')

buildid=det1[1].trim() 

Modname = det1[0].trim()

tag= det1[2].trim()

               

echo Modname               

echo buildid

                echo tag

                        

}
于 2020-09-28T10:15:10.967 回答
0

如果您没有单个 sh 命令而是一个 sh 命令块,则返回标准输出将不起作用。

我有一个类似的问题,我应用了一些不是一种干净的方法,但最终它起作用并达到了目的。

解决方案 - 在 shell 块中,回显该值并将其添加到某个文件中。在 shell 块外和脚本块内,读取此文件,修剪它并将其分配给任何本地/参数/环境变量。

例子 -

steps {
     script {
            sh '''
               echo $PATH>path.txt
               // I am using '>' because I want to create a new file every time to get the newest value of PATH
            '''
            path = readFile(file: 'path.txt')
            path = path.trim() //local groovy variable assignment

            //One  can assign these values to env and params as below  - 
            env.PATH = path  //if you want to assign it to env var
            params.PATH  = path //if you want to assign it to params var


     }
}

于 2021-04-08T09:05:17.730 回答
-7

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

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

请注意,不是简单的单引号是反引号(`)。

于 2018-11-16T06:46:31.870 回答