Sling Academy
Home/Kotlin/Capturing Output from System Commands in Kotlin

Capturing Output from System Commands in Kotlin

Last updated: November 30, 2024

When working with Kotlin, there may be situations where you need to execute system commands and capture their output. This can be useful for interacting with the operating system, automating system tasks, and retrieving data from command-line applications. In this article, we'll explore how to execute system commands in Kotlin and capture their output effectively.

Using the ProcessBuilder Class

The ProcessBuilder class is a flexible way to start and manage system processes in Java, and it can be used seamlessly in Kotlin. Let's see a basic example of how to run a system command and capture its output:


fun executeCommand(command: String): String {
    val process = ProcessBuilder(command.split(" "))
        .redirectErrorStream(true)
        .start()
    return process.inputStream.bufferedReader().readText()
}

fun main() {
    val commandOutput = executeCommand("ls -l")
    println("Command Output:\n$commandOutput")
}

In the code above, we define a function executeCommand that takes a command string, splits it into a list, and then uses ProcessBuilder to execute it.

  • Split Command: We split the command string to pass each argument separately to ProcessBuilder.
  • Redirect Error Stream: redirectErrorStream(true) merges standard error with standard output, allowing us to capture all output in one stream.
  • Read Text: We capture the output by reading from the inputStream of the process.

Handling Process Output and Errors Separately

Sometimes you might want to handle standard output and standard error separately. Here’s how you can achieve that:


fun executeCommandWithSeparateStreams(command: String): Pair {
    val process = ProcessBuilder(command.split(" ")).start()
    val output = process.inputStream.bufferedReader().readText()
    val error = process.errorStream.bufferedReader().readText()
    return output to error
}

fun main() {
    val (output, error) = executeCommandWithSeparateStreams("ls -l")
    println("Standard Output:\n$output")
    println("Standard Error:\n$error")
}

This code separately captures standard output and error by reading text from both inputStream and errorStream.

Synchronous Execution and Exit Code

In some cases, you may need not only to capture the output but also to wait for the completion and get the exit code of the command:


fun executeCommandAndWait(command: String): Int {
    val process = ProcessBuilder(command.split(" ")).start()
    val exitCode = process.waitFor()
    val output = process.inputStream.bufferedReader().readText()
    println("Output:\n$output")
    return exitCode
}

fun main() {
    val exitCode = executeCommandAndWait("ls -l")
    println("Exit Code: $exitCode")
}

Here, waitFor() is used to block the current thread until the process terminates. This is useful when you need to ensure the completion of the command execution before proceeding. With these examples, you've learned how to capture and manage the output from system commands using Kotlin. Whether you want a quick output capture or detailed error and process handling, Kotlin’s interoperability with Java’s ProcessBuilder class offers powerful tools for system interaction.

Next Article: Executing Shell Scripts Using Kotlin

Previous Article: Running System Commands from Kotlin Code

Series: Kotlin - File & OS

Kotlin

You May Also Like

  • How to Use Modulo for Cyclic Arithmetic in Kotlin
  • Kotlin: Infinite Loop Detected in Code
  • Fixing Kotlin Error: Index Out of Bounds in List Access
  • Setting Up JDBC in a Kotlin Application
  • Creating a File Explorer App with Kotlin
  • How to Work with APIs in Kotlin
  • What is the `when` Expression in Kotlin?
  • Writing a Script to Rename Multiple Files Programmatically in Kotlin
  • Using Safe Calls (`?.`) to Avoid NullPointerExceptions in Kotlin
  • Chaining Safe Calls for Complex Operations in Kotlin
  • Using the Elvis Operator for Default Values in Kotlin
  • Combining Safe Calls and the Elvis Operator in Kotlin
  • When to Avoid the Null Assertion Operator (`!!`) in Kotlin
  • How to Check for Null Values with `if` Statements in Kotlin
  • Using `let` with Nullable Variables for Scoped Operations in Kotlin
  • Kotlin: How to Handle Nulls in Function Parameters
  • Returning Nullable Values from Functions in Kotlin
  • Safely Accessing Properties of Nullable Objects in Kotlin
  • How to Use `is` for Nullable Type Checking in Kotlin