Reputation: 9938
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}"
Upvotes: 232
Views: 436517
Reputation: 1
Complementing emles-kz's answer
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 + '\n').getBytes(encoding))
inputCatcher.flush()
}
inputCatcher.write('exit\n'.getBytes(encoding))
inputCatcher.flush()
proc.consumeProcessOutput(outputCatcher, errorCatcher)
proc.waitFor()
return [new String(outputCatcher.toByteArray(), encoding), new String(errorCatcher.toByteArray(), encoding)]
}
// On Mac or Linux
def out = exec("utf-8", "/", "/bin/sh", ["echo 'test\n'", "ls", "cd usr", "echo", "ls"])
// On Windows
def out = exec("utf-8", "C:", "cmd", ["cd..", "dir"])
println "OUT:\n" + out[0]
println "ERR:\n" + out[1]
Upvotes: 0
Reputation: 51
command = "ls *"
def execute_state=sh(returnStdout: true, script: command)
but if the command fails, the process will terminate.
Upvotes: -7
Reputation: 99
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]
Upvotes: 8
Reputation: 69035
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).
Upvotes: 29
Reputation: 9938
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
Upvotes: 300
Reputation: 3659
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.
Upvotes: 41
Reputation: 26742
"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()
Upvotes: 67
Reputation: 2069
// 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()
}
Upvotes: 39