Groovy执行shell命令

Bob*_*ann 162 groovy

Groovy添加了execute方法,String使执行shell相当容易;

println "ls".execute().text
Run Code Online (Sandbox Code Playgroud)

但如果发生错误,则没有结果输出. 是否有一种简单的方法可以同时获得标准错误和标准错误? (除了创建一堆代码;创建两个线程来读取两个输入流,然后使用父流等待它们完成然后将字符串转换回文本?)

有类似的东西会很高兴;

 def x = shellDo("ls /tmp/NoFile")
 println "out: ${x.out} err:${x.err}"
Run Code Online (Sandbox Code Playgroud)

Bob*_*ann 181

好的,我自己解决了;

def sout = new StringBuilder(), serr = new StringBuilder()
def proc = 'ls /badDir'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"
Run Code Online (Sandbox Code Playgroud)

显示:

out> err> ls: cannot access /badDir: No such file or directory

  • 如果您还需要将**Environment Variables**设置为此进程,请确保将命令包装在shell中.例如,使用env vars运行Perforce命令:`envVars = ["P4PORT = p4server:2222","P4USER = user","P4PASSWD = pass","P4CLIENT = p4workspace"]; workDir = new File("path"); cmd ="bash -c \"p4 change -o 1234 \""; proc = cmd.execute(envVars,workDir);` (11认同)
  • @srikanth waitForProcess()输出文档还说"如果你不关心标准或错误输出就使用这个方法,只想让进程静默运行" - 我想要输出 (4认同)
  • 文档说我们应该使用waitForProcessOutput() - "等待输出完全消耗,调用waitForProcessOutput()".资料来源:http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Process.html#consumeProcessOutput(java.io.OutputStream,%20java.io.OutputStream) (2认同)

Jos*_*hua 44

"ls".execute()返回一个Process对象,这就是为什么"ls".execute().text有效.您应该能够只读取错误流以确定是否有任何错误.

有一个额外的方法Process允许您传递一个StringBuffer来检索文本:consumeProcessErrorStream(StringBuffer error).

例:

def proc = "ls".execute()
def b = new StringBuffer()
proc.consumeProcessErrorStream(b)

println proc.text
println b.toString()
Run Code Online (Sandbox Code Playgroud)


mho*_*815 29

// a wrapper closure around executing a string                                  
// can take either a string or a list of strings (for arguments with spaces)    
// prints all output, complains and halts on error                              
def runCommand = { strList ->
  assert ( strList instanceof String ||
           ( strList instanceof List && strList.each{ it instanceof String } ) \
)
  def proc = strList.execute()
  proc.in.eachLine { line -> println line }
  proc.out.close()
  proc.waitFor()

  print "[INFO] ( "
  if(strList instanceof List) {
    strList.each { print "${it} " }
  } else {
    print strList
  }
  println " )"

  if (proc.exitValue()) {
    println "gave the following error: "
    println "[ERROR] ${proc.getErrorStream()}"
  }
  assert !proc.exitValue()
}
Run Code Online (Sandbox Code Playgroud)

  • +1这会在输出生成时逐步显示输出.这对于长时间运行的过程非常重要 (9认同)
  • 要使用此解决方案,请发出以下行:`runCommand("echo HELLO WORLD")` (3认同)

Ani*_*kur 20

在上面提供的答案中添加一个更重要的信息 -

对于一个过程

def proc = command.execute();
Run Code Online (Sandbox Code Playgroud)

总是试着用

def outputStream = new StringBuffer();
proc.waitForProcessOutput(outputStream, System.err)
//proc.waitForProcessOutput(System.out, System.err)
Run Code Online (Sandbox Code Playgroud)

而不是

def output = proc.in.text;
Run Code Online (Sandbox Code Playgroud)

在groovy中执行命令后捕获输出,因为后者是阻塞调用(原因SO问题).


sol*_*333 20

我觉得这更惯用:

def proc = "ls foo.txt doesnotexist.txt".execute()
assert proc.in.text == "foo.txt\n"
assert proc.err.text == "ls: doesnotexist.txt: No such file or directory\n"
Run Code Online (Sandbox Code Playgroud)

正如另一篇文章提到的,这些是阻塞调用,但由于我们想要使用输出,这可能是必要的.


小智 5

def exec = { encoding, execPath, execStr, execCommands ->

def outputCatcher = new ByteArrayOutputStream()
def errorCatcher = new ByteArrayOutputStream()

def proc = execStr.execute(null, new File(execPath))
def inputCatcher = proc.outputStream

execCommands.each { cm ->
    inputCatcher.write(cm.getBytes(encoding))
    inputCatcher.flush()
}

proc.consumeProcessOutput(outputCatcher, errorCatcher)
proc.waitFor()

return [new String(outputCatcher.toByteArray(), encoding), new String(errorCatcher.toByteArray(), encoding)]

}

def out = exec("cp866", "C:\\Test", "cmd", ["cd..\n", "dir\n", "exit\n"])

println "OUT:\n" + out[0]
println "ERR:\n" + out[1]
Run Code Online (Sandbox Code Playgroud)

  • @AmosBordowitz我不是官方的downvote解释者,我不能告诉你为什么不这样,而且我不确定,因为我们谈论的是另一个人采取的行动,这是可以理解的.我提供了一种可能性.为什么不解释downvote,当然,为什么不解释答案中的代码?无论如何,我相信我们一切都会好起来的. (4认同)
  • 我真的很生气,一个人花时间给出一个答案,有人只是因为没有明显的理由而对它进行了贬低.如果这是一个社区,人们应该感到有义务添加评论(除非这是一个非常明显的理由,任何有能力的程序员会立即看到)解释downvote. (3认同)
  • @ChrisBaker那么为什么不指出呢?你自己并不肯定这是原因.. (3认同)
  • @AmosBordowitz很多答案都被否决了。没关系,这是一票否决票。就是说,这可能是因为它的代码没有解释的用语-并不总是被人们所接受。 (2认同)
  • @ChrisBaker我从未提出过任何此类主张(“但我想你更了解”)。这是礼貌的问题,不是知识的问题。 (2认同)