Groovy adds the execute method to String to make executing shells fairly easy;

println "ls".execute().text 

but if an error happens, then there is no resulting output. Is there an easy way to get both the standard error and standard output? (other than creating a bunch of code to create two threads to read both inputstreams, using a parent stream to wait for them to complete, and then convert the strings back to text?)

It would be nice to have something like;

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

7 Answers

Ok, solved it myself;

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

displays:

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

5

"ls".execute() returns a Process object which is why "ls".execute().text works. You should be able to just read the error stream to determine if there were any errors.

There is a extra method on Process that allow you to pass a StringBuffer to retrieve the text: consumeProcessErrorStream(StringBuffer error).

Example:

def proc = "ls".execute() def b = new StringBuffer() proc.consumeProcessErrorStream(b) println proc.text println b.toString() 
2

I find this more idiomatic:

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" 

As another post mentions, these are blocking calls, but since we want to work with the output, this may be necessary.

// 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() } 
4

To add one more important piece of information to the previous answers:

For a process

def proc = command.execute(); 

always try to use

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

rather than

def output = proc.in.text; 

to capture the outputs after executing commands in Groovy as the latter is a blocking call (SO question for reason).

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] 
9
command = "ls *" def execute_state=sh(returnStdout: true, script: command) 

but if the command fails, the process will terminate.

6

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.