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.
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.
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.
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.
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.
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
- Use lists for arguments: They avoid splitting problems and make quoting predictable.
- Wait before reading: Call
waitFor()before readingtextorerr. - Check the exit code: A zero exit code is success; anything else needs handling.
- Set timeouts: Use
waitFor(timeout, unit)for commands that might hang.
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
List all Groovy tutorials.