command() DSL for running programs and shell commands. It supports synchronous execution, asynchronous spawning, and streaming output via Kotlin coroutines.
Running commands
Basic execution
val output = command("echo", "Hello, world!").output()
println(output.stdoutText) // "Hello, world!"
println(output.exitCode) // 0
Shell commands
val result = shell("ls -la /data/data/com.klyx").outputText()
Adding arguments
val output = command("ls")
.arg("-la")
.args("/path/to/dir", "/another/path")
.outputText()
Environment variables
val output = command("myapp")
.env("HOME", "/data/data/com.klyx/files")
.env(mapOf("PATH" to "/usr/bin:/bin"))
.output()
Working directory
val output = command("git", "status")
.cwd(Paths.projects)
.outputText()
Synchronous output
// Get stdout as text
val text: String = command("echo", "hi").outputText()
// Get stdout as lines
val lines: List<String> = command("ls").outputLines()
// Check success/failure
val success: Boolean = command("test", "-f", path).isSuccess()
val failed: Boolean = command("false").isFailure()
// Get full output with exit code
val result: ProcessOutput = command("ls").output()
result.exitCode // Int
result.stdoutText // String
result.stderrText // String
result.stdout // ByteArray
result.stderr // ByteArray
Streaming output
// Stream stdout line by line
command("logcat").stream().collect { event ->
when (event) {
is ProcessOutputEvent.Stdout -> println(event.data.decodeToString())
is ProcessOutputEvent.Stderr -> System.err.println(event.data.decodeToString())
is ProcessOutputEvent.ExitCode -> println("Exited with ${event.code}")
}
}
// Alternative stream helpers
command("ping", "-c", "4", "google.com").streamLines().collect { line ->
println(line)
}
command("some-command").streamErrLines().collect { line ->
System.err.println(line)
}
command("log").combinedLines().collect { line ->
println(line)
}
command("build").stdoutBytes().collect { chunk ->
// Process binary output
}
command("build").stderrBytes().collect { chunk ->
// Process binary error output
}
Spawning processes
val process: ChildProcess = command("myserver").spawn()
// Wait for completion
val output: ProcessOutput = process.waitFor()
val outputOrNull: ProcessOutput? = process.waitForTimeout(5000)
// Stream output from a running process
process.streamLines().collect { line -> println(line) }
// Control the process
process.pid // Process ID
process.isRunning // Check if running
process.kill() // SIGKILL
process.terminate() // SIGTERM
Utility functions
// Check if a program exists
val exists: Boolean = commandExists("git")
// Find the full path of a program
val path: String? = which("python3")
// Find the first available program
val available: String? = firstAvailable("node", "nodejs", "deno")
// Run a command wrapped in shell
shell("curl https://api.example.com").output()
// Pipe commands
command("echo", "hello").pipeTo(command("wc", "-c"))
Advanced execution
// Timeout
val result: ProcessOutput? = command("slow-command").outputWithTimeout(10.seconds)
// Retry on failure
val result: ProcessOutput = command("flaky-command").retry(times = 3)
// Result wrapper
val result: Result<ProcessOutput> = command("risky-command").result()
result.getOrNull() // ProcessOutput? on success
result.exceptionOrNull() // Throwable? on failure
// Input to stdin
command("sort")
.stdin("c\na\nb")
.outputLines() // [a, b, c]
command("sort")
.stdin(byteArrayOf(...))
.output()
Stdin sources
StdinSource.Inherit // Inherit from parent
StdinSource.Pipe // Pipe (no initial input)
StdinSource.Bytes(data) // Provide bytes
Stdio destinations
StdioDest.Inherit // Inherit from parent
StdioDest.Capture // Capture in ProcessOutput
StdioDest.Null // Discard
StdioDest.File(file) // Write to file