# 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.
    

```bash
# 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.
    

```bash
# 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()`](file:DependsOn()). Below is an example of importing and using the **TSID** class from an external library.
    

```bash
$ 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.
    

```bash
#!/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

* [kscript - Having fun with Kotlin scripting](https://github.com/holgerbrandl/kscript)
    
* [Type-safety in the shell with kscript](https://medium.com/outbrain-engineering/type-safety-in-the-shell-with-kscript-7dd40d022537)
    
* [Scripting with Kotlin - kscript](https://craigrussell.io/2019/02/scripting-with-kotlin-kscript/)
