Executing Kotlin scripts in command shell

Hi,

I would like to replace a bash script with a kotlin script.
Therefore Shebang support Wikipedia shebang
would be helpful.

I noticed that you can add a shebang line to a kotlin script, but executing it gives some error message.

Ok: ~/kotlinc/bin/kotlinc -script list_folders.kts .
but: ~/kotlinc/bin/kotlin list_folders.kts .
error: running Kotlin scripts is not yet supported

I would like to use:
ln -s ~/kotlinc/bin/kotlin /usr/local/bin/kotlin
./list_folders.kts .

when adding #!/usr/local/bin/kotlin to the script file.

Sincerely
Dirk

2 Likes

Currently the only way to run a Kotlin script from the command line is:

kotlinc -script file.kts <arguments>

The kotlin command is going to support running scripts at some point, but as the error message says, it’s not yet done.

As a temporary solution you can use kscript GitHub - kscripting/kscript: Scripting enhancements for Kotlin

This is what I did:

#!/usr/bin/env kotlinc -script

import java.io.File

val folders: Array<out File> = File(args[0]).listFiles { file -> file.isDirectory }!!

folders.forEach { folder -> println(folder) }
2 Likes

I’m not associated with kscript, but after trying it I want to post that I recommend taking a look.
I was skeptical after looking at the implementation ( a fairly complex looking shell script) that it would be any
better, especially performance, then Atlan’s suggestion (which works fine and does with in simplicity points).
But a simple ‘1 liner’ test (and then an hour later not-so-simple because I didn’t believe it) –

Put the above in a file ( I had to change to ‘#!/my/path/to/kotlinc -script’) /tmp/file.kts

then try a simple test:

time /tmp/file.kts

Run that a few times

Then delete the first line (the shebang) and try again with kscript
For me - the very first run of kscripts was infinitesimally longer (added about .001s)
But after that 10-40x shorter every run (depends on script complexity and what its doing).
Using kotlinc directly makes no measurable difference.

kotlinc:

real    0m2.074s
user    0m4.377s
sys     0m0.133s


kscript


real    0m0.166s
user    0m0.145s
sys     0m0.066s

Note the user time – 4.377 sec for kotlnc, .145 for kscript. > 30x diff

That’s why I didn’t believe it :slight_smile: kscript is a 1 file shell script – its not doing anything really fancy or complicated - nothing you can’t do yourself or do without - except convenience … but I doubt I could do better easily so Im not going to bother.

Leaving the ‘pre-compiled’ script cached is a huge win – if you are using a script more than once. If you are not, its still a big win because the performance and simplicity is equivalent but you don’t have to do things differently each time.
JVM startup time is bad enough that it makes JVM CLI apps non-performant in many scripting use cases,
add to that the compile startup time and now looking at 2+ maybe FIVE secs per invocation – that pushes it over the line
for ‘no brainer’ script replacements – put that in a for loop or multiple $(script) calls and your simple scripts take minutes instead of seconds or less. Dropping that down to a .1s appx startup overhead brings it back to the realm of reasonable ‘no brainer’ script use cases.

Maybe someday kotlin will optimize the startup - until then, I’m going with kscript
-David

2 Likes

Any updates on this?

kscript is better then ever.
kotlinc still works, and under the hood kscript calls it – but kscript manages a lot of tedious cache logic and has evolved to have a lot more features – they are nearly identical to the scripting features in IntelliJ IDE – but I dont know of any cli which implements those.

Did this not give you an error?
error: unable to instantiate class test.Test (test.kts): java.lang.NoClassDefFoundError: kotlin/script/templates/standard/ScriptTemplateWithArgs