System Command Execution (exec)

The Golo exec module allows you to execute external system commands similar to Go’s os/exec package, with idiomatic Golo error handling using exceptions and Result types.

Overview

The exec module provides an interface for executing system commands and capturing their output. It follows the idiomatic Golo approach:

Main Function

execCommand(commandName, args...)

Creates a Command object for executing an external command.

Parameters:

Returns:

Example:

let cmd = execCommand("ls", "-la", "/tmp")

execCombinedOutput(cmd)

Executes the command and returns combined output (stdout + stderr).

Parameters:

Returns:

Example with try/catch:

try {
  let output = execCombinedOutput(execCommand("ls", "-la"))
  println(output)
} catch (e) {
  println("Error:", e)
}

Example with Result (functional):

import gololang.Errors

let result = trying(-> execCombinedOutput(execCommand("whoami")))

either(result,
  |output| -> println("User:", output: trim()),
  |err| -> println("Error:", err)
)

Error Handling

Imperative approach: try/catch

try {
  let cmd = execCommand("ls", "/tmp")
  let output = execCombinedOutput(cmd)
  println("Success:", output)
} catch (e) {
  println("Error:", e)
}

Functional approach: Result type

import gololang.Errors

# Wrapper to get a Result
let result = trying(-> execCombinedOutput(execCommand("pwd")))

# Check the type
if isOk(result) {
  println("Output:", result: value())
} else {
  println("Error:", result: message())
}

# Or use either()
either(result,
  |output| -> println("Success:", output),
  |err| -> println("Error:", err)
)

Functional Approach with Result

Helper functions

import gololang.Errors

# Execute and return a Result
function execResult = |cmd| {
  return trying(-> execCombinedOutput(cmd))
}

# Execute and return output or empty string
function execQuiet = |cmd| {
  let result = trying(-> execCombinedOutput(cmd))
  return orElse(result, "")
}

Composition with mapResult

let result = trying(-> execCombinedOutput(execCommand("date")))
let upperDate = mapResult(result, |output| -> output: toUpperCase())

either(upperDate,
  |output| -> println(output),
  |err| -> println("Error:", err)
)

Chaining with flatMapResult

let pipeline = flatMapResult(
  execResult(execCommand("whoami")),
  |user| {
    return flatMapResult(
      execResult(execCommand("pwd")),
      |dir| {
        return Result(user + " @ " + dir)
      }
    )
  }
)

either(pipeline,
  |info| -> println(info),
  |err| -> println("Error:", err)
)

Examples

Example 1: Simple command with try/catch

#!/usr/bin/env golo

module examples.SimpleCommand

function main = |args| {
  try {
    let output = execCombinedOutput(execCommand("ls", "-la", "/tmp"))
    println(output)
  } catch (e) {
    println("Error:", e)
  }
}

Example 2: Error handling with Result

#!/usr/bin/env golo

module examples.ResultStyle

import gololang.Errors

function main = |args| {
  let result = trying(-> execCombinedOutput(execCommand("whoami")))

  either(result,
    |output| -> println("User:", output: trim()),
    |err| -> println("Error:", err)
  )
}

Example 3: Collecting multiple commands

import gololang.Errors

function main = |args| {
  let commands = list[
    execCommand("pwd"),
    execCommand("whoami"),
    execCommand("date")
  ]

  let results = commands
    : map(|cmd| -> trying(-> execCombinedOutput(cmd)))
    : filter(|result| -> isOk(result))
    : map(|result| -> result: value(): trim())

  foreach output in results {
    println(output)
  }
}

Functional Patterns

Filter

Filter successful commands:

let commandsToCheck = list["git", "docker", "node", "nonexistent"]

let available = commandsToCheck
  : map(|cmd| -> trying(-> execCombinedOutput(execCommand("which", cmd))))
  : filter(|result| -> isOk(result))
  : map(|result| -> result: value(): trim())

Map transformation

let dateResult = trying(-> execCombinedOutput(execCommand("date")))
let formatted = mapResult(dateResult, |output| {
  return output: toUpperCase(): trim()
})

Chaining (flatMap)

let info = flatMapResult(
  trying(-> execCombinedOutput(execCommand("whoami"))),
  |user| {
    return mapResult(
      trying(-> execCombinedOutput(execCommand("hostname"))),
      |host| -> user: trim() + "@" + host: trim()
    )
  }
)

Lazy evaluation

let lazyCommand = |cmd| -> || {
  let result = trying(-> execCombinedOutput(cmd))
  return orElse(result, "")
}

let lazyDate = lazyCommand(execCommand("date"))
# Execute only when called
println(lazyDate())

Best Practices

  1. Use Result for functional code: Prefer trying() and either() for a functional style
  2. Try/catch for imperative code: Use try/catch for simple procedural style
  3. Clean output: Use trim() to remove whitespace and newlines
  4. Compose with helpers: Create reusable execResult() and execQuiet() functions
  5. Secure handling: Avoid executing commands built from unvalidated user input

Useful Result Functions

Important Notes

© 2026 GoloScript Project | Built with Gu10berg

Subscribe: 📡 RSS | ⚛️ Atom