Groovy ejecutando comandos de shell


Groovy agrega el método execute a String para hacer que ejecutar shells sea bastante fácil;

println "ls".execute().text

Pero si ocurre un error, entonces no hay salida resultante. ¿Hay una manera fácil de obtener tanto el error estándar como la salida estándar? (aparte de crear un montón de código para; crear dos hilos para leer ambos inputstreams, a continuación, utilizando un flujo padre para esperar a que se completen y luego convertir las cadenas de nuevo a texto?)

Sería bueno tener algo como;

 def x = shellDo("ls /tmp/NoFile")
 println "out: ${x.out} err:${x.err}"
 119
Author: cdeszaq, 2008-10-01

7 answers

Ok, lo resolví yo 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

 136
Author: Bob Herrmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-07 15:00:55

"ls".execute() devuelve un objeto Process por lo que "ls".execute().text funciona. Debería poder leer el flujo de errores para determinar si hubo errores.

Hay un método extra 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()
 35
Author: Joshua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-07 14:34:02
// 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()
}
 23
Author: mholm815,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-04 20:06:40

Para agregar una información más importante a las respuestas proporcionadas anteriormente -

Para un proceso

def proc = command.execute();

Siempre intente 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 groovy ya que este último es una llamada de bloqueo ( SO question for reason).

 18
Author: Aniket Thakur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:49

Encuentro esto más idiomático:

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 menciona otro post, estas son llamadas de bloqueo, pero como queremos trabajar con la salida, esto puede ser necesario.

 9
Author: solstice333,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-10 22:43:05
command = "ls *"

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

Pero si el comando falla el proceso terminará

 5
Author: 舒何伟,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-13 04:03:01
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]
 4
Author: emles-kz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-22 03:31:17