Groovy Shell (groovysh) – Interactive REPL with 10 Tested Examples

The Groovy Shell (groovysh) REPL is covered here with 10 tested examples. Learn commands, tab completion, multi-line input, imports, and scripting tips on Groovy 5.x.

“The best way to learn a language is to have a conversation with it. A REPL is that conversation.”

Brian Kernighan, The Unix Programming Environment

Last Updated: March 2026 | Tested on: Groovy 5.x, Java 17+ | Difficulty: Beginner | Reading Time: 14 minutes

If you’ve installed Groovy and want a quick way to experiment with code without creating files, the Groovy Shell (groovysh) is your best friend. As described in the official Groovy integration documentation, it’s an interactive REPL (Read-Eval-Print Loop) that ships with every Groovy installation. You type an expression, press Enter, and see the result immediately. No compilation step, no boilerplate, no project setup.

This post covers how to launch groovysh, use its built-in commands, handle multi-line input, import libraries, define classes and methods on the fly, load external scripts, pull in dependencies with @Grab, inspect objects, and understand when to use groovysh versus the other Groovy execution tools.

If you’re brand new to Groovy, start with our Groovy Hello World tutorial. If you’ve already used the groovy -e command for one-liners, this is the natural next step – see our Groovy Command Line -e Option guide for comparison.

What Is groovysh?

groovysh is the interactive command-line shell that ships with the Groovy SDK. It provides a REPL environment where you can type Groovy expressions and statements, see results immediately, and build up code incrementally. Think of it as a scratchpad for Groovy – perfect for learning, prototyping, testing API calls, and debugging.

Key features of groovysh:

  • Instant feedback – every expression is evaluated and the result is printed immediately
  • Tab completion – press Tab to auto-complete class names, method names, and variables
  • Multi-line input – define classes, closures, and complex statements across multiple lines
  • Built-in commands:help, :clear, :load, :save, :quit, and more
  • History – arrow keys navigate through previous commands, and history persists across sessions
  • Import support – import any class on the classpath, including @Grab dependencies

Getting Started with groovysh

To launch the Groovy Shell, open a terminal and type:

Launching groovysh

groovysh

You’ll see a prompt like this:

Groovy Shell (5.0.0, JVM: 17.0.x)
Type ':help' or ':h' for help.
-------------------------------------
groovy:000>

The groovy:000> prompt tells you the shell is ready. The number after the colon is the line counter within the current buffer. When you type a complete statement and press Enter, the shell evaluates it and prints the result prefixed with ===>.

You can also launch groovysh with options:

  • groovysh -q – quiet mode, suppresses the startup banner
  • groovysh -cp /path/to/lib/* – add JARs to the classpath
  • groovysh -D property=value – set system properties
  • groovysh -e "println 'hello'" – evaluate an expression and exit

10 Practical Examples

Let’s work through 10 tested examples that cover the key techniques for being productive in groovysh. Every example below was tested on Groovy 5.x with Java 17+.

Example 1: Launching groovysh and Basic Expressions

What we’re doing: Evaluating basic arithmetic, string operations, and Groovy expressions directly in the shell. This is the simplest use case – treating groovysh as a calculator and quick-test environment.

Example 1: Basic Expressions in groovysh

// Arithmetic
groovy:000> 2 + 3
===> 5

// String interpolation
groovy:000> name = "Groovy"
===> Groovy
groovy:000> "Hello, ${name}!"
===> Hello, Groovy!

// List operations
groovy:000> [1, 2, 3, 4, 5].collect { it * 2 }
===> [2, 4, 6, 8, 10]

// Map literal
groovy:000> [language: 'Groovy', version: '5.0']
===> [language:Groovy, version:5.0]

// Type checking
groovy:000> 42.class
===> class java.lang.Integer
groovy:000> "hello".class
===> class java.lang.String

// Boolean expressions
groovy:000> 10 > 5 && "groovy".startsWith("g")
===> true

Notice that you don’t need println to see results. The REPL automatically prints the return value of each expression after the ===> marker. If an expression returns null, the shell prints ===> null. When you use println, the output appears on its own line before the ===> marker.

Understanding the result indicator: The ===> output is the return value of the expression, not standard output. This distinction matters. If you type println "hello", you’ll see hello on one line (that’s stdout) followed by ===> null (that’s the return value, since println returns void/null). If you type "hello" by itself, you’ll only see ===> hello because the string expression’s return value is the string itself.

This is a great place to experiment with Groovy’s operators and GDK methods. Try things like "hello" * 3, [1,2,3] + [4,5], or (1..10).step(2) and see what comes back. The instant feedback loop is what makes a REPL so effective for learning.

Example 2: Variables and Multi-line Input

What we’re doing: Declaring variables and writing multi-line statements. The shell detects incomplete code (like an unclosed brace or parenthesis) and waits for more input.

Example 2: Variables and Multi-line Input

// Variables persist across lines in the same session
groovy:000> firstName = "John"
===> John
groovy:000> lastName = "Doe"
===> Doe
groovy:000> "${firstName} ${lastName}"
===> John Doe

// Using def keyword
groovy:000> def age = 30
===> 30
groovy:000> age
===> 30

// Multi-line input - the shell detects the opening brace
groovy:000> def greet(name) {
groovy:001>     return "Welcome, ${name}!"
groovy:002> }
===> true
groovy:000> greet("Alice")
===> Welcome, Alice!

// Multi-line closures
groovy:000> def numbers = [3, 1, 4, 1, 5, 9, 2, 6]
===> [3, 1, 4, 1, 5, 9, 2, 6]
groovy:000> numbers.findAll {
groovy:001>     it > 3
groovy:002> }.sort()
===> [4, 5, 6, 9]

// Multi-line if/else
groovy:000> x = 42
===> 42
groovy:000> if (x > 40) {
groovy:001>     "big number"
groovy:002> } else {
groovy:003>     "small number"
groovy:004> }
===> big number

When you open a brace, parenthesis, or bracket, the shell prompt changes from groovy:000> to groovy:001>, groovy:002>, and so on. This tells you the shell is waiting for more input to complete the statement. Once all brackets are balanced and the statement is complete, the shell evaluates it.

Important note on def: Variables declared with def in groovysh are scoped to the current evaluation. If you want a variable to persist across multiple inputs, omit the def keyword – this binds the variable to the shell’s binding context. For more on def, see our Groovy def Keyword guide.

A quick test to see the difference:

def Scoping in groovysh

// Without def - variable persists
groovy:000> color = "blue"
===> blue
groovy:000> color
===> blue

// With def - variable is local to that evaluation
groovy:000> def shape = "circle"
===> circle
groovy:000> shape
ERROR groovy.lang.MissingPropertyException:
No such property: shape for class: groovysh_evaluate

This behavior catches many beginners off guard. The rule is simple: if you want to keep it, don’t use def. This is the opposite of how def works in a regular Groovy script, where def declares a local variable within the script’s scope.

Example 3: Built-in Commands (:help, :clear, :quit, :load, :save)

What we’re doing: Exploring the built-in colon commands that control the shell itself. These are not Groovy code – they’re shell meta-commands that start with a colon.

Example 3: Built-in Commands

// Display all available commands
groovy:000> :help
Available commands:
  :help      (:h ) Display this help message
  :?         (:? ) Alias to: :help
  :exit      (:x ) Exit the shell
  :quit      (:q ) Alias to: :exit
  :import    (:i ) Import a class into the namespace
  :display   (:d ) Display the current buffer
  :clear     (:c ) Clear the buffer and reset the prompt counter
  :show      (:S ) Show variables, classes, or imports
  :inspect   (:n ) Inspect a variable or last result with the GUI object browser
  :purge     (:p ) Purge variables, classes, imports, or preferences
  :edit      (:e ) Edit the current buffer
  :load      (:l ) Load a file or URL into the buffer
  :save      (:s ) Save the current buffer to a file
  :record    (:r ) Record the current session to a file
  :history   (:H ) Display, manage, and recall edit-line history
  :alias     (:a ) Create an alias
  :set       (:= ) Set (or list) preferences
  :grab      (:g ) Add a dependency to the shell environment
  :register  (:rc) Register a new command with the shell
  :doc       (:D ) Open a browser window displaying the doc for the argument

// Clear the current buffer (useful if you started typing something wrong)
groovy:000> x = 10
===> 10
groovy:000> :clear
groovy:000>

// Show all variables in the current session
groovy:000> name = "Groovy"
===> Groovy
groovy:000> version = 5
===> 5
groovy:000> :show variables
Variables:
  name = Groovy
  version = 5

// Show all imports
groovy:000> :show imports
imports:
  ...default imports...

// Show command history
groovy:000> :history
  1  name = "Groovy"
  2  version = 5
  3  :show variables

// Exit the shell
groovy:000> :quit

Each command has a long form (like :help) and a short alias (like :h). You’ll use :clear frequently when you make a typo in a multi-line statement and want to start over. The :show variables command is handy for checking what’s currently defined in your session.

The :purge command is worth knowing about separately. It lets you selectively clean up your session:

  • :purge variables – removes all variables from the binding
  • :purge classes – removes all class definitions
  • :purge imports – removes all user-added imports (default imports remain)
  • :purge all – clears everything and resets the session to a clean state

The :set command controls shell preferences. For example, :set show-last-result false stops the shell from printing the ===> result line after each expression. Run :set with no arguments to see all available preferences and their current values.

Example 4: Tab Completion and Code Assistance

What we’re doing: Using tab completion to discover methods, properties, and class names without leaving the shell. This is one of the most productive features of groovysh.

Example 4: Tab Completion

// Type a string and press Tab after the dot to see available methods
groovy:000> "hello".to [TAB]
toBoolean()     toCharacter()   toDouble()      toFloat()
toInteger()     toList()        toLong()        toLowerCase()
toSet()         toShort()       toString()      toUpperCase()
toURI()         toURL()

// Complete class names
groovy:000> java.util.Array [TAB]
ArrayList       ArrayDeque      Arrays

// Complete after partial method name
groovy:000> [1,2,3].col [TAB]
collect(        collectEntries( collectMany(    collectNested(

// Works with your own variables too
groovy:000> myMap = [a: 1, b: 2, c: 3]
===> [a:1, b:2, c:3]
groovy:000> myMap.find [TAB]
find(           findAll(        findResult(     findResults(

// Tab on an empty line after an import shows all available classes
groovy:000> import java.time.Local [TAB]
LocalDate       LocalDateTime   LocalTime

Tab completion works on class names, method names, variable names, and even package names. It introspects the actual objects at runtime, so it shows methods that are really available – including GDK (Groovy Development Kit) methods that Groovy adds to Java classes. This makes groovysh a great tool for API exploration.

Pro tip: If tab completion seems slow on the first use, that’s because the shell is loading class metadata. Subsequent completions in the same session are much faster. You can also use the :doc command to open Javadoc/Groovydoc in a browser for any class: :doc java.util.HashMap opens the HashMap documentation directly.

Tab completion is context-aware. If you type new java.util. and press Tab, it shows classes you can instantiate. If you type a variable name followed by a dot and press Tab, it shows the methods and properties available on that specific object’s type. This runtime introspection is more accurate than static analysis because it reflects the actual state of the object.

Example 5: Importing Classes and Packages

What we’re doing: Importing classes into the shell session so you can use them without fully qualified names. Groovy’s default imports are already available, but you’ll often need additional ones.

Example 5: Importing Classes

// Groovy's default imports are already available
groovy:000> new Date()
===> Tue Mar 10 14:30:00 IST 2026

groovy:000> new ArrayList()
===> []

// Import additional classes with the import statement
groovy:000> import java.time.LocalDate
===> java.time.LocalDate
groovy:000> LocalDate.now()
===> 2026-03-10

// Import with alias
groovy:000> import java.time.format.DateTimeFormatter as DTF
===> java.time.format.DateTimeFormatter
groovy:000> LocalDate.now().format(DTF.ofPattern("dd-MMM-yyyy"))
===> 10-Mar-2026

// Use the :import command (equivalent)
groovy:000> :import java.util.concurrent.atomic.AtomicInteger
groovy:000> counter = new AtomicInteger(0)
===> 0
groovy:000> counter.incrementAndGet()
===> 1

// Import static members
groovy:000> import static java.lang.Math.PI
===> java.lang.Math.PI
groovy:000> PI
===> 3.141592653589793

// Wildcard import
groovy:000> import java.nio.file.*
===> java.nio.file.*
groovy:000> Files.exists(Path.of("/tmp"))
===> true

// Check all current imports
groovy:000> :show imports

Groovy automatically imports java.lang.*, java.util.*, java.io.*, java.net.*, groovy.lang.*, groovy.util.*, java.math.BigDecimal, and java.math.BigInteger. Everything else needs an explicit import. Once imported in a session, the import persists until you close the shell or use :purge imports.

Example 6: Defining Classes and Methods in REPL

What we’re doing: Creating classes, methods, and closures directly in the shell. This is useful for prototyping data structures and algorithms before committing them to a file.

Example 6: Defining Classes and Methods

// Define a simple class
groovy:000> class Person {
groovy:001>     String name
groovy:002>     int age
groovy:003>     String toString() { "${name} (age: ${age})" }
groovy:004> }
===> true

// Create instances
groovy:000> alice = new Person(name: "Alice", age: 30)
===> Alice (age: 30)
groovy:000> bob = new Person(name: "Bob", age: 25)
===> Bob (age: 25)

// Use the class
groovy:000> people = [alice, bob]
===> [Alice (age: 30), Bob (age: 25)]
groovy:000> people.sort { it.age }
===> [Bob (age: 25), Alice (age: 30)]

// Define a standalone method
groovy:000> def factorial(n) {
groovy:001>     n <= 1 ? 1 : n * factorial(n - 1)
groovy:002> }
===> true
groovy:000> factorial(10)
===> 3628800

// Define and use closures
groovy:000> doubler = { it * 2 }
===> groovysh_evaluate$_run_closure1@3a71c100
groovy:000> (1..5).collect(doubler)
===> [2, 4, 6, 8, 10]

// Enum definitions work too
groovy:000> enum Color { RED, GREEN, BLUE }
===> true
groovy:000> Color.values()
===> [RED, GREEN, BLUE]
groovy:000> Color.GREEN.name()
===> GREEN

// Show all defined classes
groovy:000> :show classes

Classes defined in the shell live for the duration of the session. You can redefine a class by entering the same class definition again – the new definition replaces the old one. However, existing instances of the old class won’t be updated. If you get into a messy state, use :purge classes to clear all class definitions and start fresh.

Interfaces and traits work too. You can define interfaces, abstract classes, and even Groovy traits directly in the REPL:

Interfaces and Traits in groovysh

// Define a trait
groovy:000> trait Greetable {
groovy:001>     String greet() { "Hello, I'm ${name}" }
groovy:002> }
===> true

// Use it in a class
groovy:000> class Employee implements Greetable {
groovy:001>     String name
groovy:002>     String department
groovy:003> }
===> true

groovy:000> emp = new Employee(name: "Carol", department: "Engineering")
===> Employee@4a5905d9
groovy:000> emp.greet()
===> Hello, I'm Carol

This makes groovysh a complete prototyping environment. You can define full class hierarchies, test their interactions, and iterate on the design before moving the code to a proper project file.

Example 7: Loading External Scripts with :load

What we’re doing: Loading Groovy scripts from disk into the shell session. This lets you prepare utility functions in a file and bring them into your interactive session.

Example 7: Loading External Scripts

// First, assume we have a file called utils.groovy with this content:
// --- utils.groovy ---
// def add(a, b) { a + b }
// def multiply(a, b) { a * b }
// greeting = "Hello from utils.groovy!"
// println "Utils loaded successfully."
// --- end of file ---

// Load the script into the shell
groovy:000> :load utils.groovy
Utils loaded successfully.
===> Hello from utils.groovy!

// Now the functions and variables are available
groovy:000> add(3, 7)
===> 10
groovy:000> multiply(4, 5)
===> 20
groovy:000> greeting
===> Hello from utils.groovy!

// Load from an absolute path
groovy:000> :load /home/user/scripts/helpers.groovy

// Load from a URL
groovy:000> :load https://example.com/scripts/sample.groovy

// Save the current session to a file
groovy:000> x = 10
===> 10
groovy:000> y = 20
===> 20
groovy:000> x + y
===> 30
groovy:000> :save session.groovy

// Record the session (captures everything you type)
groovy:000> :record start mySession.txt
Recording current session to: mySession.txt
groovy:000> println "This will be recorded"
This will be recorded
===> null
groovy:000> :record stop
Recording stopped; session saved to: mySession.txt

The :load command executes the script as if you had typed each line into the shell. Variables and methods defined in the script become available in the current session. The :save command writes the contents of the current buffer to a file. The :record command captures your entire interactive session, which is useful for creating tutorials or documenting exploration sessions.

Creating a reusable startup script: A common pattern is to create a file called groovysh-init.groovy with your frequently used imports, utility methods, and configuration. Then start each session with :load groovysh-init.groovy. Here’s an example of what that file might contain:

Sample groovysh-init.groovy

// groovysh-init.groovy - load this at the start of each session
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import groovy.json.JsonSlurper
import groovy.json.JsonOutput

// Utility methods
def now() { LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) }
def parseJson(text) { new JsonSlurper().parseText(text) }
def prettyJson(obj) { JsonOutput.prettyPrint(JsonOutput.toJson(obj)) }

println "Session initialized at ${now()}"
println "Available: now(), parseJson(text), prettyJson(obj)"

With this file loaded, you have instant access to date formatting and JSON utilities without typing the imports every time. This is especially valuable if you use groovysh daily for data exploration or API testing.

Example 8: Using @Grab in groovysh

What we’re doing: Pulling in external dependencies directly from Maven repositories using @Grab. This makes groovysh a useful tool for testing third-party libraries without a build file. For more details into dependency management, see our Groovy Grape guide.

Example 8: Using @Grab in groovysh

// Grab Apache Commons Lang for string utilities
groovy:000> :grab 'org.apache.commons:commons-lang3:3.14.0'
groovy:000> import org.apache.commons.lang3.StringUtils
===> org.apache.commons.lang3.StringUtils
groovy:000> StringUtils.capitalize("groovy shell")
===> Groovy shell
groovy:000> StringUtils.reverse("hello")
===> olleh

// Alternative: use @Grab annotation syntax
groovy:000> @Grab('com.google.code.gson:gson:2.11.0')
groovy:001> import com.google.gson.Gson
===> com.google.gson.Gson
groovy:000> gson = new Gson()
===> {}
groovy:000> gson.toJson([name: "Alice", age: 30])
===> {"name":"Alice","age":30}

// Parse JSON back
groovy:000> json = '{"city":"London","pop":9000000}'
===> {"city":"London","pop":9000000}
groovy:000> gson.fromJson(json, Map)
===> {city=London, pop=9000000.0}

// Use Groovy's built-in JSON support (no @Grab needed)
groovy:000> import groovy.json.JsonSlurper
===> groovy.json.JsonSlurper
groovy:000> new JsonSlurper().parseText('{"framework":"Grails","version":7}')
===> [framework:Grails, version:7]

// Grab with specific repository
groovy:000> @GrabResolver(name='jcenter', root='https://jcenter.bintray.com/')
groovy:001> @Grab('org.codehaus.gpars:gpars:1.2.1')
groovy:002> import groovyx.gpars.GParsPool

The :grab command and @Grab annotation both use Grape, Groovy’s built-in dependency manager. The first time you grab a dependency, it downloads from Maven Central (or whichever repository you specify) and caches it in ~/.groovy/grapes/. Subsequent uses load from cache. This makes groovysh incredibly useful for quickly testing a library’s API before adding it to your project’s build file.

Troubleshooting @Grab in groovysh: If @Grab throws a resolution error, check your network connection and proxy settings. You can configure proxy settings in ~/.groovy/grapeConfig.xml. If a dependency has transitive conflicts, use @GrabExclude to exclude specific transitive dependencies. Also, remember that @Grab resolves dependencies at the point it’s evaluated – so it must appear before the import statement for the classes you want to use from that dependency.

For a complete guide on Grape’s configuration options, repository management, and advanced dependency resolution, see our dedicated Groovy Grape post.

Example 9: Inspecting Objects and Types

What we’re doing: Examining object types, available methods, properties, and class hierarchies. The REPL is an excellent tool for runtime introspection.

Example 9: Inspecting Objects and Types

// Check the type of any expression
groovy:000> 42.class
===> class java.lang.Integer
groovy:000> 42.class.name
===> java.lang.Integer
groovy:000> 3.14.class
===> class java.math.BigDecimal
groovy:000> [1, 2, 3].class
===> class java.util.ArrayList

// List all methods on an object
groovy:000> "hello".metaClass.methods*.name.unique().sort()
===> [asBoolean, asType, capitalize, center, charAt, chars, ...]

// Check if an object responds to a method
groovy:000> "hello".respondsTo("toUpperCase")
===> [public java.lang.String java.lang.String.toUpperCase(), ...]
groovy:000> "hello".respondsTo("nonExistent")
===> []

// Explore properties
groovy:000> myList = [10, 20, 30]
===> [10, 20, 30]
groovy:000> myList.metaClass.properties*.name
===> [class, empty]
groovy:000> myList.empty
===> false

// Inspect class hierarchy
groovy:000> Integer.superclass
===> class java.lang.Number
groovy:000> Integer.interfaces*.name
===> [java.lang.Comparable]

// The :inspect command opens a visual object browser (if GUI is available)
groovy:000> data = [name: "Groovy", version: 5, features: ["REPL", "DSL", "AST"]]
===> [name:Groovy, version:5, features:[REPL, DSL, AST]]
groovy:000> :inspect data

// Use dump() for a quick text dump
groovy:000> new Date().dump()
===> <java.util.Date@... fastTime=1741598400000 ...>

// Use .properties for JavaBean-style inspection
groovy:000> import java.time.LocalDate
===> java.time.LocalDate
groovy:000> today = LocalDate.now()
===> 2026-03-10
groovy:000> today.properties
===> [dayOfWeek:TUESDAY, dayOfMonth:10, month:MARCH, year:2026, ...]

// Get GDK methods added by Groovy
groovy:000> (String.metaClass.methods - java.lang.String.methods)*.name.unique().sort().take(10)
===> [asBoolean, asType, capitalize, center, collectReplacements, ...]

This kind of introspection is what makes a REPL so valuable. Instead of reading documentation, you can poke at live objects, discover their methods, and test them immediately. The combination of tab completion (Example 4) and runtime inspection gives you a very fast feedback loop for learning new APIs.

Practical use case – exploring an unfamiliar API: Imagine you need to work with Java’s java.time API but aren’t sure what methods are available on LocalDate. Instead of searching the Javadoc, you can do this:

Exploring APIs Interactively

groovy:000> import java.time.LocalDate
===> java.time.LocalDate
groovy:000> today = LocalDate.now()
===> 2026-03-10

// What methods start with "plus"?
groovy:000> today.metaClass.methods*.name.findAll { it.startsWith("plus") }.unique()
===> [plusDays, plusWeeks, plusMonths, plusYears]

// Try one
groovy:000> today.plusWeeks(2)
===> 2026-03-24

// What about "get" methods?
groovy:000> today.metaClass.methods*.name.findAll { it.startsWith("get") }.unique().sort()
===> [getChronology, getClass, getDayOfMonth, getDayOfWeek, getDayOfYear, getEra, getLong, getMonth, getMonthValue, getYear]

groovy:000> today.getDayOfWeek()
===> TUESDAY
groovy:000> today.getDayOfYear()
===> 69

This interactive discovery workflow is significantly faster than switching between your editor and documentation. You can test edge cases, verify behavior, and build confidence in an API before writing production code.

Example 10: groovysh vs groovyConsole vs groovy -e

What we’re doing: Comparing the three main ways to run Groovy code interactively. Each has its sweet spot, and knowing when to use which saves time.

Example 10: Comparison of Groovy Execution Tools

// === groovysh (Interactive REPL) ===
// Launch: groovysh
// Best for: exploration, learning, API testing, quick calculations
// Features: tab completion, history, :commands, session persistence
//
// groovy:000> [1,2,3].sum()
// ===> 6

// === groovyConsole (GUI Editor + REPL) ===
// Launch: groovyConsole
// Best for: writing longer scripts with visual feedback, AST inspection
// Features: syntax highlighting, AST browser, output pane, script editor
//
// Write code in the editor area, press Ctrl+R to run
// def result = (1..100).findAll { it % 7 == 0 }
// println result

// === groovy -e (One-liner Execution) ===
// Launch: groovy -e 'println "Hello"'
// Best for: shell scripts, CI/CD pipelines, quick one-off commands
// Features: non-interactive, can be piped, works in shell scripts
//
// $ groovy -e 'println new Date().format("yyyy-MM-dd")'
// 2026-03-10

Here’s a side-by-side comparison table to help you choose:

FeaturegroovyshgroovyConsolegroovy -e
InterfaceCommand-line REPLGUI (Swing-based)Single command
InteractiveYesYesNo
Tab completionYesNoNo
Multi-line editingLine by lineFull editorSingle expression
Syntax highlightingNoYesNo
AST browserNoYesNo
Session historyYes (persistent)Per windowNo
Best forExploration, learningPrototyping scriptsAutomation, CI/CD
SSH friendlyYesNo (needs display)Yes
@Grab supportYesYesYes

Rule of thumb: Use groovysh when you want to explore and experiment interactively on a terminal. Use groovyConsole when you want a visual editor with syntax highlighting and the AST browser. Use groovy -e when you need a one-liner in a shell script or CI pipeline. For more on the -e option, check out our Groovy Command Line -e Option guide.

When to use groovysh specifically:

  • Learning Groovy syntax – test each concept as you read about it
  • Exploring a new library’s API@Grab it, import it, and call methods to see what they do
  • Quick data transformations – parse a JSON file, filter some data, format the output
  • Debugging – reproduce an issue in isolation by copying the relevant code into the REPL
  • Working on remote servers via SSH – no GUI needed, just a terminal
  • Quick calculations – it’s a powerful calculator that understands dates, strings, collections, and math

When NOT to use groovysh:

  • Writing scripts longer than 20-30 lines – use a proper editor and run with groovy scriptname.groovy
  • Code that needs syntax highlighting – use groovyConsole or your IDE
  • Automated pipelines – use groovy -e or run a script file directly
  • AST debugginggroovyConsole has a built-in AST browser that groovysh lacks

Best Practices

Session Management

  • Avoid def for variables you want to reuse – Variables declared with def in groovysh are scoped to the current evaluation buffer. Omit def to bind variables to the shell session so they persist across inputs.
  • Use :record for important sessions – When you’re exploring an API or debugging a problem, start recording with :record start filename.txt. You’ll thank yourself later when you need to reproduce what you did.
  • Use :clear liberally – If you’re mid-way through a multi-line statement and realize you made a mistake, :clear resets the buffer instantly rather than trying to fix the syntax error.
  • Create startup scripts – Place commonly used imports and utility functions in a file and :load it at the start of each session to save repetitive typing.

Performance and Memory

  • Watch memory in long sessions – Every variable and class definition stays in memory. For long exploration sessions, use :purge variables or :purge all periodically to free resources.
  • Use -cp instead of @Grab for large libraries – If you’re repeatedly using the same libraries, launching groovysh -cp /path/to/libs/* is faster than @Grab because it skips the dependency resolution step.
  • Increase heap for heavy work – Set JAVA_OPTS="-Xmx512m" before launching groovysh if you’re working with large datasets or many dependencies.

Productivity Tips

  • Use arrow keys for history – Up/Down arrows navigate through previous commands. The history persists across sessions in ~/.groovy/groovysh.history.
  • Ctrl+R for reverse search – Just like in Bash, Ctrl+R searches your command history backward. Type a fragment and it finds the last matching command.
  • Use _ for the last result – The underscore variable _ holds the result of the last evaluated expression, so you can chain operations without assigning intermediate results to variables.
  • Pipe output for scripting – Combine groovysh with shell pipelines: echo 'println System.properties["os.name"]' | groovysh -q.

Common Pitfalls to Avoid

  • Don’t confuse groovysh with the system shell – Shell commands like ls, cd, or dir don’t work in groovysh. If you need to run system commands, use "ls -la".execute().text (Groovy’s process execution). See our Groovy Hello World guide for the basics.
  • Don’t redefine a class and expect old instances to update – If you create alice = new Person(name: "Alice"), then redefine class Person with new fields, alice still references the old class definition. Create new instances after redefining.
  • Watch out for semicolons – Unlike some REPLs, groovysh treats each line as a potential complete statement. If you want multiple statements on one line, separate them with semicolons: x = 10; y = 20; x + y.
  • Don’t ignore error messages – When you get a MissingPropertyException or MissingMethodException, read the message carefully. It often tells you the exact class where the lookup failed, which helps diagnose whether you have a scoping issue, a typo, or a missing import.
  • Beware of infinite loops – If you accidentally create an infinite loop in groovysh, press Ctrl+C to interrupt it. The shell will catch the interrupt and return you to the prompt. If Ctrl+C doesn’t work, you may need to close the terminal.

Environment Configuration

You can customize groovysh behavior through environment variables and configuration files:

  • GROOVY_HOME – Must point to your Groovy installation directory
  • JAVA_OPTS – Set JVM options like -Xmx512m for increased heap or -Dhttp.proxyHost=... for proxy configuration
  • ~/.groovy/groovysh.profile – If this file exists, groovysh loads it automatically at startup. Place your default imports and utility methods here for zero-effort session initialization
  • ~/.groovy/groovysh.history – Command history is persisted here across sessions. You can edit or clear this file manually if needed

The groovysh.profile file is particularly powerful. Unlike :load, which you run manually each session, the profile runs automatically every time you start groovysh. Put your most common imports, date/JSON utilities, and database connection helpers there, and they’ll always be available.

Conclusion

The Groovy Shell (groovysh) is one of the most underused tools in the Groovy ecosystem. It gives you instant feedback, tab completion, session persistence, and the ability to pull in any Maven dependency on the fly with @Grab. It works well for learning Groovy, prototyping algorithms, testing library APIs, and debugging data transformations – all faster than creating a project and writing a full script.

We covered 10 practical examples: from basic expressions and multi-line input to built-in commands, tab completion, imports, class definitions, loading scripts, dependency management, object inspection, and the comparison between Groovy’s three execution tools. With these techniques, you can make groovysh a central part of your Groovy workflow.

Summary

  • groovysh is a REPL that ships with every Groovy installation – no extra setup required
  • Tab completion and command history make exploration fast and efficient
  • Built-in commands like :help, :clear, :load, :save, and :record manage your session
  • @Grab pulls in any Maven dependency on the fly – no build file needed
  • Omit def for session-persistent variables; use def for temporary ones
  • :load brings external scripts into your session for reusable utility functions
  • Runtime introspection with .class, .metaClass, and .properties is invaluable for learning APIs

If you also work with build tools, CI/CD pipelines, or cloud CLIs, check out Command Playground to practice 105+ CLI tools directly in your browser — no install needed.

Up next: Groovy Custom Annotations

Frequently Asked Questions

What is groovysh and how do I start it?

groovysh is the interactive REPL (Read-Eval-Print Loop) shell that ships with every Groovy installation. To start it, open a terminal and type groovysh. You’ll see a prompt like groovy:000> where you can type Groovy expressions and see results immediately. It requires no project setup, no build files, and no IDE – just a working Groovy installation.

How do I handle multi-line code in groovysh?

groovysh automatically detects incomplete statements. When you type an opening brace {, parenthesis (, or bracket [, the prompt counter increments (e.g., groovy:001>) and waits for more input. Once all brackets are balanced and the statement is complete, the shell evaluates it. If you make a mistake in a multi-line block, type :clear to reset the buffer and start over.

Why does my variable disappear after I define it with def in groovysh?

Variables declared with def in groovysh are scoped to the current evaluation context. To create a variable that persists across multiple inputs in the same session, omit the def keyword – for example, write name = "Alice" instead of def name = "Alice". This binds the variable to the shell’s global binding, making it accessible throughout the session.

Can I use external libraries in groovysh?

Yes. You can pull in any Maven dependency using the :grab command (e.g., :grab 'org.apache.commons:commons-lang3:3.14.0') or the @Grab annotation. Groovy’s Grape dependency manager downloads the JAR from Maven Central and caches it locally. You can also launch groovysh with a classpath: groovysh -cp /path/to/jars/* for faster startup when using the same libraries repeatedly.

What is the difference between groovysh, groovyConsole, and groovy -e?

groovysh is a command-line REPL with tab completion and session history – ideal for interactive exploration on a terminal. groovyConsole is a GUI application with a script editor, syntax highlighting, and an AST browser – best for writing and testing longer scripts visually. groovy -e executes a single Groovy expression non-interactively – perfect for shell scripts and CI/CD pipelines. All three support @Grab for dependency management.

Previous in Series: Groovy Logging

Next in Series: Groovy Custom Annotations

Related Topics You Might Like:

This post is part of the Groovy Cookbook series on TechnoScripts.com

RahulAuthor posts

Avatar for Rahul

Rahul is a passionate IT professional who loves to sharing his knowledge with others and inspiring them to expand their technical knowledge. Rahul's current objective is to write informative and easy-to-understand articles to help people avoid day-to-day technical issues altogether. Follow Rahul's blog to stay informed on the latest trends in IT and gain insights into how to tackle complex technical issues. Whether you're a beginner or an expert in the field, Rahul's articles are sure to leave you feeling inspired and informed.

No comment

Leave a Reply

Your email address will not be published. Required fields are marked *