2008-10-01 21 views
103

Groovy agrega el método execute al String para hacer que los shells de ejecución sean bastante fáciles;Groovy ejecutando comandos de shell

println "ls".execute().text 

pero si ocurre un error, no hay salida resultante. ¿Existe alguna manera fácil de obtener el error estándar y el estándar? (además de crear un montón de código para; crear dos subprocesos para leer ambos flujos de entrada, luego usar una secuencia primaria para esperar a que se completen y luego convertir las cadenas de nuevo a texto?)

Sería bueno tener algo me gusta;

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

este [link] (http://opensourceforgeeks.blogspot.in/2014/08/executing-shell-commands-in-groovy.html) es útil. Muestra cómo ejecutar el comando de shell con la demo de cURL. –

Respuesta

113

Ok, resuelto mí mismo;

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

muestra:

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

+8

En caso de que también necesite establecer ** Variables de entorno ** en este proceso, asegúrese de ajustar el comando en shell.Por ejemplo, ejecutar un comando Perforce con env vars: 'envVars = [" P4PORT = p4server: 2222 "," P4USER = usuario "," P4PASSWD = pass "," P4CLIENT = p4workspace "]; workDir = new File ("ruta"); cmd = "bash -c \" p4 change -o 1234 \ ""; proc = cmd.execute (envVars, workDir); ' –

+0

@paul_sns no relacionado con la pregunta OP, pero creo que las JVM modernas manejan la sincronización sin supervisión muy bien. Por lo tanto, es poco probable que StringBuffer degrade el rendimiento en escenarios confinados a hilos o apilados. –

+2

Los documentos dicen que deberíamos usar waitForProcessOutput() - "Para esperar que la salida se consuma por completo, llame waitForProcessOutput()". Fuente: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Process.html#consumeProcessOutput(java.io.OutputStream,%20java.io.OutputStream) – Srikanth

29

"ls".execute() devuelve un objeto Process razón por la cual "ls".execute().text obras. Debería poder leer la secuencia de error para determinar si hubo algún error.

Hay un método adicional en Process que le permite pasar un StringBuffer para recuperar el texto: consumeProcessErrorStream(StringBuffer error).

Ejemplo:

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() 
} 
+8

+1 Esto muestra la salida de forma incremental a medida que se genera la salida ... que es extremadamente importante para un proceso largo –

+0

gran parte allí @ mholm815 –

15

Para añadir una información más importante respuestas proporcionadas anteriormente -

Para un proceso

def proc = command.execute(); 

Siempre trate de usar

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

en lugar de

def output = proc.in.text; 

para capturar las salidas después de ejecutar comandos en el maravilloso ya que esta última es una llamada de bloqueo (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] 
+2

Estoy realmente molesto porque una persona se tomó el tiempo para dar una respuesta y alguien simplemente lo rechazó sin razón aparente. si se trata de una comunidad, uno debería sentirse obligado a agregar un comentario (a menos que sea una razón muy obvia que cualquier programador competente vería de inmediato) explicando el voto a la baja. –

+1

@AmosBordowitz Muchas respuestas obtienen votos atrasados. Está bien, es un voto negativo. Dicho esto, podría ser porque es un código sin una palabra de explicación, no siempre bien recibido. –

+0

@ChrisBaker ¿por qué no lo señala? Usted mismo no está seguro de que esta sea la razón. –

5

Me parece más idiomática:

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" 

Como se menciona otro post, se trata de llamadas de bloqueo, pero ya que queremos trabajar con la salida, esto puede ser necesario.

2
command = "ls *" 

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

pero si el comando falla el proceso terminará

Cuestiones relacionadas