2008-10-01 44 views
103

Groovy добавляет метод execute к String, чтобы сделать исполняемые оболочки довольно простыми;Groovy, выполняющий команды оболочки

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. – 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

Если вам также необходимо установить ** Переменные среды ** для этого процесса, обязательно заверните команду в оболочку.Например, запуск команды Perforce с env vars: `envVars = [" P4PORT = p4server: 2222 "," P4USER = пользователь "," P4PASSWD = pass "," P4CLIENT = p4workspace "]; workDir = новый файл («путь»); 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) 

но если провал команды процесс прекращается

Смежные вопросы