2008-10-01 284 views
103

Groovy將execute方法添加到String以使執行的shell非常簡單;Groovy執行shell命令

println "ls".execute().text 

但是如果發生錯誤,那麼沒有結果輸出。 有沒有簡單的方法來獲得標準錯誤和標準?(除了創建一堆代碼;創建兩個線程來讀取兩個輸入流,然後使用父流等待它們完成,然後將字符串轉換回文本?)

這將是很好有東西喜歡;

def x = shellDo("ls /tmp/NoFile") 
println "out: ${x.out} err:${x.err}" 
+0

此[鏈接](http://opensourceforgeeks.blogspot.in/2014/08/executing-shell-commands-in-groovy.html)是有用的。演示如何使用cURL演示運行shell命令。 – 2014-08-16 06:02:17

回答

113

好了,解決了它自己;

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

顯示:

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

+8

如果您還需要將** 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);` – 2013-11-05 09:39:08

+0

@paul_sns與OP問題無關,但我認爲現代JVM處理無爭用同步就好了。所以StringBuffer不太可能會降低線程或堆棧限制的情況下的性能。 – 2016-06-14 15:42:41

+2

該文檔說,我們應該使用waitForProcessOutput() - 「等待輸出完全消耗呼叫waitForProcessOutput()」。來源:http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Process.html#consumeProcessOutput(java.io.OutputStream,%20java.io.OutputStream) – Srikanth 2016-08-12 06:58:32

29

"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() 
22
// 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() 
} 
15

要一個更重要的信息添加到上述提供的答案 -

對於過程

def proc = command.execute(); 

總是嘗試使用

def outputStream = new StringBuffer(); 
proc.waitForProcessOutput(outputStream, System.err) 
//proc.waitForProcessOutput(System.out, System.err) 

而非

def output = proc.in.text; 

在常規執行命令,因爲後者是一個阻塞呼叫(SO question for reason)之後捕獲輸出。

4
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] 
5

我覺得這是更地道:

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" 

正如另一篇文章提到,這些都是阻止呼叫,但因爲我們希望與輸出工作,這可能是必要的。

2
command = "ls *" 

def execute_state=sh(returnStdout: true, script: command) 

但如果命令失敗的過程將終止