ZetCode

Groovy Process Execution

last modified October 15, 2026

Groovy scripts often need to run other programs, such as a build tool, a version check, or a system utility. Groovy adds the execute method to strings and lists, and it exposes the Java ProcessBuilder for more control. This tutorial covers both approaches, reading output, checking exit codes, and handling timeouts.

Running a Command with execute

A string or list can be turned into a process with execute(). The call returns immediately, so use waitFor() to wait for the program to finish. The text property reads the standard output.

SimpleExecute.groovy
def process = "echo Hello from a child process".execute()
process.waitFor()

println process.text
println "Exit code: ${process.exitValue()}"

waitFor() blocks until the command ends, then text returns everything it printed. Always wait before reading the output, or the read may return partial data.

Passing Arguments as a List

A string is split on spaces, which breaks arguments that contain spaces. Pass a list instead so each argument is kept as one item.

ListArguments.groovy
def command = ["echo", "two words", "stay together"]
def process = command.execute()
process.waitFor()

println process.text

The list form passes two words as a single argument. This matters for file names and user input that may contain spaces.

Reading Errors and Exit Codes

Standard output and standard error are separate streams. Read in for standard output and err for error messages. Read each stream only once, because reading text closes it. and check exitValue() to see whether the command succeeded. A non-zero exit code means failure.

ErrorsAndExitCode.groovy
def process = ["ls", "/no/such/directory"].execute()
process.waitFor()

println "Exit code: ${process.exitValue()}"
println "Stdout: ${process.in.text.trim() ?: '(empty)'}"
println "Stderr: ${process.err.text.trim()}"

Here ls fails, so the exit code is not zero, and the error message is available from err. Because ls prints nothing to standard output, the stdout line shows (empty). Checking both is the reliable way to know what happened.

Controlling the Process with ProcessBuilder

ProcessBuilder lets you set the working directory, environment variables, and whether errors are merged into the output. Call start() to launch the process.

ProcessBuilderExample.groovy
def builder = new ProcessBuilder("pwd")
builder.directory(new File("/tmp"))
builder.redirectErrorStream(true)

def process = builder.start()
process.waitFor()

println "Directory: ${process.text.trim()}"

The working directory is set to /tmp, and redirectErrorStream(true) sends errors into the same stream, so one read collects everything.

Timeouts

A command that hangs can block a script forever. Java 8 and later provide waitFor(timeout, unit), which returns false when the time runs out. Then destroy the process.

Timeout.groovy
import java.util.concurrent.TimeUnit

def process = ["sleep", "5"].execute()

if (!process.waitFor(1, TimeUnit.SECONDS)) {
    process.destroy()
    println "Timed out and stopped"
} else {
    println "Finished with ${process.exitValue()}"
}

The sleep 5 command runs longer than the one-second limit, so the script stops it. Without the timeout check, the script would wait the full five seconds.

Security Note

Never pass untrusted input into a command string. Build the command as a list with fixed program names, and validate arguments. Commands built by joining user text can run unintended programs.

Best Practices

Source

Java ProcessBuilder API | Groovy Development Kit

Groovy makes running external programs short, and ProcessBuilder covers the cases that need more control. Read both output streams, check the exit code, and set a timeout whenever a command could hang.

Author

My name is Jan Bodnar, and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Groovy tutorials.