Kommand ~ Kotlin Command Line DSL

Kommand is essentially Java’s Process class and its associated libs wrapped up in a nicer package.

Commands can be easily piped into each other, by calling another command on top of the other. And no process is created until out() is called. out() returns a Flow of output from the pipeline of commands, which can then be operated on with any method that extends a Kotlin Flow<String> or whatever type you decide to transform it into.

It has all of the Unix command line hits, but may be missing something you’re looking for. In that case, feel free to extend it and submit a pull request.

Examples:

check the number of gradle files in the current directory

fun main() = runBlocking {

    shell { }
        .ls { -"a" }
        .grep { -"e" of "gradle" }
        .wc { -"w" }
        .out()
        .collect { println(it) }
}
    shell { }
        .ping(host = "google.com") { }
        .out()
        .collect { println(it) }

Run a custom script and observe the output:

    shell { }
        .cd(dir = "some/path/to/bash-scripts") { }
        .kommand { +"./some_bash_script.sh" } 
        .out()
        .collect { println(it) }

Go up one directory and run ls:

    shell { }
        .cd(dir = "..") { }
        .ls { }
        .out()
        .collect { println(it) }

Execute a command without a special extension method using the generic kommmand() method:

    shell { }
        .ls { }
        .kommand("wc") { -"w" }
        .out()
        .collect { println(it) }

Add/update variables in environment and print out for sanity check:

    shell { 
        env {
            "LD_LIBRARY_PATH" to "LD_LIBRARY_PATH:/some/other/dynamic/lib"
            "JAVA_HOME" to "path/to/java/we/want/to/use" 
        } 
    }
        .env
        .entries
        .forEach { println(it) }
# Output: 
# LD_LIBRARY_PATH=LD_LIBRARY_PATH:/some/other/dynamic/lib
# JAVA_HOME=path/to/java/we/want/to/use

Add/update variables on the fly with the export() method:

    shell {
        env {
            "LD_LIBRARY_PATH" to "LD_LIBRARY_PATH:/some/other/dynamic/lib"
            "JAVA_HOME" to "path/to/java/we/want/to/use"
        }
    }
        .export { "KRB5CC" to "/dev/null" }
        .env
        .entries
        .forEach { println(it) }
# Output: 
# LD_LIBRARY_PATH=LD_LIBRARY_PATH:/some/other/dynamic/lib
# JAVA_HOME=path/to/java/we/want/to/use
# KRB5CC=/dev/null 

Take a certain number of outputs and then automatically destroy all the processes that were used to get them:

    shell { }
        .cd(dir = "../log") { }
        .ls { }
        .sort { }
        .out()
        .take(10)
        .toList()
        .collect { 
            println("top ten log files: $it")
        }

Argument Syntax

There are currently three main styles to using arguments with a given command:

Given the above, we can assume that a command such as

    shell { }
        .grep {   
            -"i" 
            +"mr_tube" 
            +"users.txt"
        }

would be equivalent to entering grep -i mr_tube users.txt at the command line.

Some Kommand methods have explicit parameters, such as cd(dir: String)–this is mostly only currently in the spots where it (usually) doesn’t make sense to use the command without that argument.