Learn Groovy - Scripting & Command-Line Automation
Episode 8 of 23

Learn Groovy - Scripting & Command-Line Automation

This episode takes you into the world of Groovy scripting for task automation: parsing command-line arguments, reading environment variables, file handling, text processing, and managing log output. You will build a CLI script ready for production use.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Groovy was born for scripting, and this episode is the most direct manifestation of that purpose. You'll learn to write scripts that can be run from the terminal to automate repetitive tasks — from processing files to checking system conditions.

Episode 8 covers parsing command-line arguments, reading environment variables, file handling, text processing, and log output. After this episode, you'll create clean CLI scripts that are ready for production.

Running Scripts from the Command Line

Program Arguments

Every Groovy script has an args variable containing the command-line arguments:

Read arguments
println "Jumlah argumen: ${args.length}"
args.each { arg ->
    println "Argumen: ${arg}"
}

Run it with:

Run a script with arguments
groovy script.groovy halo dunia

groovy script.groovy halo dunia passes halo and dunia to the args variable. This args variable is available automatically in every script, without any declaration.

Simple Argument Parsing

For more complex scripts, you can process arguments manually:

Parse simple options
def mode = "dev"
def nama = "Teman"
 
for (i in 0..<args.length) {
    if (args[i] == "--mode" && i + 1 < args.length) {
        mode = args[i + 1]
    } else if (args[i] == "--nama") {
        nama = args[i + 1]
    }
}
 
println "Mode: ${mode}, Nama: ${nama}"

for (i in 0..<args.length) iterates over the arguments and checks the flags. This manual pattern is enough for small scripts; for mature option parsing, you can use Apache's commons-cli library.

Environment Variables and System Properties

Reading Environment Variables

Scripts often need to read configuration from the environment:

Read environment variables
def home = System.getenv("HOME")
println "Home directory: ${home}"
 
def apiKey = System.getenv("API_KEY") ?: "tidak-ada"
println "API key tersedia: ${apiKey != "tidak-ada"}"

System.getenv("HOME") reads an environment variable. The Elvis operator ?: provides a default value when the variable isn't set, so the script doesn't crash due to a different environment.

JVM System Properties

In addition to the environment, Groovy can read JVM system properties passed when running Java:

Read system properties
def region = System.getProperty("region", "ap-southeast-1")
println "Region: ${region}"

Run it with:

Pass a system property
groovy -Dregion=us-east-1 script.groovy

groovy -Dregion=us-east-1 script.groovy passes the region system property, and System.getProperty("region", "ap-southeast-1") reads it with a default fallback. These two configuration sources — environment and properties — will be managed further in episode 14.

File Handling and Text Processing

Reading and Writing Files

The Groovy JDK makes file operations very concise:

Read and write files
def input = new File("/tmp/sumber.txt")
def output = new File("/tmp/hasil.txt")
 
output.text = input.text.toUpperCase()
println "Isi asli: ${input.text}"
println "Isi hasil: ${output.text}"

input.text reads the entire file contents as a string, and output.text = ... writes it all at once. input.text.toUpperCase() combines string enhancements with file operations in a single line.

Processing Line by Line

For large files, process line by line to save memory:

Process a file line by line
new File("/tmp/log.txt").eachLine { baris, nomor ->
    if (baris.contains("ERROR")) {
        println "${nomor}: ${baris}"
    }
}

new File("/tmp/log.txt").eachLine { baris, nomor -> ... } iterates over each line with its number, and only prints the lines containing ERROR. This pattern is ideal for filtering logs or structured data.

For more complex matching, Groovy supports regex with slash literals, for example /(?i)error\s+\d+/, so you don't need excessive backslash escaping like in Java.

Log Output

Writing Structured Logs

Production scripts need logs that are easy for machines to read:

Structured log output
def log(String level, String pesan) {
    def waktu = new Date().format("yyyy-MM-dd HH:mm:ss")
    println "${waktu} [${level}] ${pesan}"
}
 
log("INFO", "Script dimulai")
log("WARN", "Cache belum ada, memuat ulang")
log("ERROR", "Gagal menghubungi API")

new Date().format("yyyy-MM-dd HH:mm:ss") adds a timestamp, and log("INFO", "...") produces a consistent log line. This format is easy for observability tools to parse, which we'll cover in episode 19.

Building a Complete Script

Combining All the Elements

Let's bring all the concepts together in one complete script:

Structured log backup script
def folder = System.getenv("LOG_DIR") ?: "/tmp/logs"
def pola = /\.log$/
 
def totalError = 0
new File(folder).listFiles().findAll { it.name ==~ pola }.each { file ->
    def errors = file.text.readLines().findAll { it.contains("ERROR") }
    totalError += errors.size()
    println "${file.name}: ${errors.size()} error"
}
 
println "Total error: ${totalError}"

new File(folder).listFiles().findAll { it.name ==~ pola } finds all .log files in the directory, then counts the ERROR lines in each file. This script shows how file handling, regex, environment, and collections work together in one complete program.

Closing

Episode 8 made you productive as a script writer: reading arguments with args, reading environment variables and system properties, processing files and text, and writing structured logs.

The key takeaways:

  • The args variable automatically holds the command-line arguments.
  • System.getenv reads the environment; System.getProperty reads JVM properties.
  • file.text reads and writes an entire file's contents.
  • eachLine processes large files line by line without wasting memory.
  • Slash literals /regex/ eliminate the need for excessive escaping.
  • Combine collection methods to build processing pipelines.

In episode 9 next, we'll discuss DSLs and domain-specific languages — the principles of building DSLs in Groovy, builder-style DSLs, declarative configuration, and DSL examples for deployment and testing.