如何在Jenkinsfile中获取shell脚本的输出?

9
在 Jenkinsfile Groovy 脚本的阶段中,假设我想要执行一个 Linux 命令,该命令输出一些字符串的行和列,并且我想要获取特定行输出中的第 n 列。这样的命令示例是 "ls -al"。那么,我应该这样做吗?
stage("Get dir size") {
  sh returnStatus: true, script: '''
    LINE=`ls -al | grep some_dir`
    IFS=" " read -ra COLS <<< $LINE
    echo ${COLS[4]}
  '''
  /* I want to use the value of ${COL[4]} after above block */
}

我应该如何获取“ls -al”命令的第五列,即目录大小,基本上是 ${COL[4]} 的值呢?

谢谢!

1个回答

14

您在示例中展示的这个bash脚本不会返回正确的目录大小。它将返回一个文件的大小,通常为4096字节,而不是递归地所有文件和子目录的总大小。如果您想要获取总目录大小,可以尝试类似以下内容的脚本:

您在示例中展示的这个bash脚本不会返回正确的目录大小。它将返回一个文件的大小,通常为4096字节,而不是递归地所有文件和子目录的总大小。如果您想要获取总目录大小,可以尝试类似以下内容的脚本:

#!groovy

node('master') {

  stage("Get dir size") {
    script {
      DIR_SIZE = sh(returnStdout: true, script: 'du -sb /var/jenkins_home/war/jsbundles | cut -f1')
    }
    echo "dir size = ${DIR_SIZE}"
  }
}

关键部分是使用启用了returnStdoutsh步骤,这样您可以将脚本在控制台打印出的内容捕获到变量中。在此示例中,我正在计算/var/jenkins_home/war/jsbundles文件夹的总大小,当我运行此流水线脚本时,我会得到:

dir size = 653136

您可以在后续流水线步骤中使用DIR_SIZE变量作为输入。

备选方案:使用Groovy的File.directorySize()

不必使用bash脚本,您可以考虑使用Groovy内置方法File.directorySize(),例如:

#!groovy

node('master') {

  stage("Get dir size") {
    script {
      DIR_SIZE = new File('/var/jenkins_home/war/jsbundles').directorySize()
    }
    echo "dir size = ${DIR_SIZE}"
  }
}

然而,与使用bash命令的情况相比,这种方法将给出不同的结果:

dir size = 649040

这是因为 Groovy 的 File.directorySize() 方法将结果递归地计算为所有文件大小的总和,并没有考虑目录文件的大小。在这个例子中,差异是 4096 - 目录文件 /var/jenkins_home/war/jsbundles 的大小(此路径不包含任何子文件夹,只有一堆文件)。

更新:从类似列的输出中提取数据

您可以通过将命令(如 grepcut )连在一起来从类似列的输出中提取任何信息。例如,您可以用以下方式替换上面的示例:

#!groovy

node('master') {
  stage("Get dir size") {
    script {
      DIR_SIZE = sh(returnStdout: true, script: 'ls -la /var | grep jenkins_home | cut -d " " -f5')
    }
    echo "dir size = ${DIR_SIZE}"
  }
}

以下是输出结果:

total 60
drwxr-xr-x  1 root    root    4096 Nov  4  2017 .
drwxr-xr-x  1 root    root    4096 May 31 03:27 ..
drwxr-xr-x  1 root    root    4096 Nov  4  2017 cache
dr-xr-xr-x  2 root    root    4096 May  9  2017 empty
drwxr-xr-x  2 root    root    4096 Nov  4  2017 git
drwxrwxr-x 20 jenkins jenkins 4096 May 31 12:26 jenkins_home
drwxr-xr-x  5 root    root    4096 May  9  2017 lib
drwxr-xr-x  2 root    root    4096 May  9  2017 local
drwxr-xr-x  3 root    root    4096 May  9  2017 lock
drwxr-xr-x  2 root    root    4096 May  9  2017 log
drwxr-xr-x  2 root    root    4096 May  9  2017 opt
drwxr-xr-x  2 root    root    4096 May  9  2017 run
drwxr-xr-x  3 root    root    4096 May  9  2017 spool
drwxrwxrwt  2 root    root    4096 May  9  2017 tmp

它将提取4096 - jenkins_home 文件的大小。

需要记住的事情:

  • 使用简单的 bash 脚本,如 ls -la /var | grep jenkins_home | cut -d " " -f5。你上面展示的示例在我的本地 bash 和 Jenkins 服务器中都无法工作。
  • sh 步骤中添加 returnStdout: true 参数以返回命令在控制台上输出的内容。

这里的目录大小仅为一个示例。我想要做的基本上是:1)发出类似于“ls -al”的输出列命令,2)查找一行,3)获取该行中的第n列。另一个例子是“ps -ef”或“docker image ls”。 - Chris F
我修改了我的问题。 - Chris F
@ChrisF 我已经更新了我的答案。有两件事情非常关键:将bash脚本命令进行管道处理,以便它们可以返回正确的输出(你的示例在我的Jenkins和本地bash环境中不起作用),使用returnStdout: true使sh步骤返回命令的输出,这样你就可以将其赋值给一个变量。 - Szymon Stepniak
跟进问题。我如何在脚本之外使用你的例子中的变量DIR_SIZE,并将其作为Groovy代码的一部分在阶段中使用?还是echo部分说明了这一点? - Chris F
@ChrisF 你可以像使用 echo 步骤一样使用它。 - Szymon Stepniak
1
需要注意的一点是,即使您使用了 node('other-agent') 并运行了 new File('/var/jenkins_home/war/jsbundles'),这段 Groovy 代码在 Jenkins 主节点上执行,而不是您指定的代理/执行器上。出于这个原因,它也会进行安全检查,并且在沙盒流水线中默认情况下会失败。 - mkobit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接