Writing Shell Scripts with Kotlin

Writing Shell Scripts with Kotlin

Overview

  • Bash is the most widely used and familiar script interpreter for system engineers and developers in the operating environment, but it also offers the most uncomfortable scripting language. Over the years, the development community has seen languages that ensure Type-Safety dominate in terms of productivity and maintenance, with TypeScript in the frontend and Kotlin in the backend increasing their market share. So, what about writing shell scripts with Kotlin? Node.js is already widely used for shell scripting. In this article, we will explain how to write shell scripts with Kotlin.

Installing kscript

  • kscript is a useful auxiliary tool that allows you to write shell scripts in Kotlin language. It provides several useful tools, including script cache to overcome the disadvantages of JVM. Install it as follows.
# Install SDKMAN
$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"

# Install kscript
$ sdk install kotlin
$ sdk install kscript

# Check installed version
$ kscript -v
Version   : 4.2.3
Build     : 2023-07-22T13:06:02.327407526Z
Kotlin    : 1.9.23-release-779
Java      : JRE 21.0.1+12

Writing a kscript Example

  • Now it's time to write a script.
# Writing a script
$ nano hello.kts
#!/usr/bin/env kscript
println("Hello, World!")

# Granting execution permission to the script
$ chmod +x hello.kts

# Executing the script
$ ./hello.kts
Hello, World!

# Editing with IntelliJ IDEA
$ kscript --idea hello.kts

Adding a Library Example

  • You can use remote libraries from the Maven repository at the beginning of the script by using @file:DependsOn(). Below is an example of importing and using the TSID class from an external library.
$ nano tsid.kts
#!/usr/bin/env kscript
@file:DependsOn("io.hypersistence:hypersistence-utils-hibernate-60:3.7.3")

import io.hypersistence.tsid.TSID

val tsid = TSID.fast()
println(tsid.toLong())
println(tsid.toString())
println(tsid.toLowerCase())
println(tsid.instant)

Executing External Commands Example

  • By writing a script as follows, you can execute external commands within the script.
#!/usr/bin/env kscript
import java.io.File

when ("ls -al".exec()) {
    0 -> println("SUCCESS")
    else -> {
        println("FAILED")
        kotlin.system.exitProcess(1) 
    }
}

# Returns the result of execution (0: success, others: failure)
fun String.exec(cwd: File? = null): Int {
    return ProcessBuilder(*split(" ").toTypedArray())
            .redirectErrorStream(true)
            .inheritIO()
            .directory(cwd)
            .start()
            .waitFor()
}

# Returns the execution string, throws IOException on failure
fun String.exec(cwd: File? = null): String? {
    val parts = this.split("\s".toRegex())
    val proc = ProcessBuilder(*parts.toTypedArray())
            .directory(cwd)
            .redirectOutput(ProcessBuilder.Redirect.PIPE)
            .redirectError(ProcessBuilder.Redirect.PIPE)
            .start()
    proc.waitFor()
    return proc.inputStream.bufferedReader().readText()
}

References