【问题标题】:Executing Groovy command through Jenkins: "find: missing argument to `-exec'"通过 Jenkins 执行 Groovy 命令:“查找:缺少 `-exec' 的参数”
【发布时间】:2016-05-04 17:35:05
【问题描述】:

我正在尝试使用 Jenkins 管道脚本 (groovy) 将生成的战争文件从一个构建目录复制到另一个。我已经以 jenkins 用户身份在系统本身上测试了 find/exec/cp 命令,从与脚本运行相同的工作区,它工作正常(直接从控制台复制粘贴)。

String buildNumber = env.BUILD_NUMBER

def sout = new StringBuffer()
def serr = new StringBuffer()

//Create package directory in jenkins job folder
def packageDir = "${env.JENKINS_HOME}/jobs/Package_Deploy_Pipeline/builds/${buildNumber}/package/"
def command = "mkdir ${packageDir}"
def proc = command.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(3000)
println "out> $sout err> $serr"

command = "find ${env.JENKINS_HOME}/jobs/myJob/builds/lastSuccessfulBuild/archive/build/libs/ -name *.war -exec cp {} ${packageDir} \\;"
println command
proc = command.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(3000)
println "out> $sout err> $serr"

在控制台输出中看到的错误是:

[Pipeline] echo
out>  err> 
[Pipeline] echo
find /var/lib/jenkins/jobs/myJob/builds/lastSuccessfulBuild/archive/build/libs/ -name *.war -exec cp {} /var/lib/jenkins/jobs/Package_Deploy_Pipeline/builds/23/package/ \;
[Pipeline] echo
out>  err> find: missing argument to `-exec'

编辑:我也试过"*.war"'*.war'\;';'

【问题讨论】:

  • 当前目录下是否有.war文件?这样*.war 可能会被shell 覆盖?引用这个论点有帮助吗? (我不认为这会是这里的问题,但它可能会是一个潜在的问题,无论如何你都应该解决。)(在该命令中扩展 ${env.JENKINS_HOME} 是什么?)再次转义 ; 有帮助吗?
  • 唯一的 .war 在 cp 源目录中。我确实尝试单引号'* .war'并得到相同的结果。 ${env.JENKINS_HOME} 扩展到 /var/lib/jenkins/ 我从控制台输出中知道它是正确的。我不知道你说的再次逃跑是什么意思,你能详细说明一下吗?
  • 这通常与问题无关,但 env.JENKINS_HOME 不是有效的 shell 变量。外壳不能扩展它。那么这是做什么的呢?通过再次转义它,我的意思是,执行命令的任何内容都可能是从 \; 中删除反斜杠,您应该尝试将 \\; 放入命令字符串中作为测试。
  • 啊。上面的代码是 groovy 代码。所以 ${} 在常规代码中得到扩展。我发布的控制台输出中显示的是实际收到的 shell 命令。这就是我在服务器上手动验证的。
  • 如果您在服务器上手动运行该打印命令,它是否有效?因为它看起来不错。

标签: linux bash jenkins groovy jenkins-pipeline


【解决方案1】:

带有 声明式管道的 Jenkins 仅对我有效:

sh 'find . -ipath "*src/header.h" -exec rm {} ";"'

【讨论】:

  • 谢谢! Jenkinsfiles 的语法很痛苦。
【解决方案2】:

时髦

您遇到的错误问题可能与\; 以及您正在转义bash/sh 命令有关,而实际上您没有使用bash/sh,而是运行find 可执行文件。

需要对-name 参数应用相同的方法,其中应从搜索模式中删除引号。

例子:

command = "find src -name *.txt -exec cp {} dst/ ;"
println "[cmd] ${command}"
proc = command.execute()

def sout = new StringBuffer()
def serr = new StringBuffer()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "[cmd.out] ${sout}"
println "[cmd.err] ${serr}"

詹金斯

如果您从 Jenkins 和流水线作业运行此代码,可能最方便的方法是使用内置的 sh 步骤。

sh:Shell 脚本

This step allows a Jenkins server or slave running on Linux or a Unix-like machine to execute a shell script.
Params:

script: String - the script to execute

sh "find src -name '*.txt' -exec cp {} dst/ \;"

有关 Pipeline DSL 的更多信息,请访问Pipeline tutorial

纯 Groovy

毕竟为什么不用 Groovy 代码替换 find

("src" as File).eachFileRecurse{
    if (it.name ==~ ".*\\.txt") {
        ...
    }
}

这不是更优雅吗?

【讨论】:

  • 很好的意见,谢谢。你知道内置的 sh 步骤是否允许我检查 serr 和 sout,我在教程中没有看到任何示例,所以我选择了 groovy 方法。
  • 更多关于如何从sh step, stackoverflow.com/a/36958537/6128602获取命令状态和输出的信息。
  • 谢谢您的注意。由于我有一些基于 sterr 和 sout 的更复杂的逻辑,所以我现在需要坚持使用 groovy .execute() 实现。
  • jenkins 提出的解决方案给我一个错误:unexpected char: '\'
【解决方案3】:

我没有解决命令失败的原因,但我将假设在链接命令时它的 groovys 转换为 sh 中断。我的解决方案是分解查找和复制命令。

location = "find ${env.JENKINS_HOME}/jobs/myJob/builds/lastSuccessfulBuild/archive/build/libs/ -name *.war".execute().text
command = "cp $location ${packageDir}myJob.war"
proc = command.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(3000)
println "out> $sout err> $serr"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-27
    • 2014-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多