Update: If you are in Gradle Groovy to Kotlin DSL migration all you need is this, less code you should care about and would have less unexpected (e.g. on quoted parameters) results than above code may have,
import org.codehaus.groovy.runtime.ProcessGroovyMethods
ProcessGroovyMethods.getText(ProcessGroovyMethods.execute("ls"))
// Or,
fun String.execute() = ProcessGroovyMethods.execute(this)
val Process.text: String? get() = ProcessGroovyMethods.getText(this)
// then just like groovy, "ls".execute().text
I wanted a few changes from the solution of jkschneider, as it didn't catch the error codes I got from the executed commands. Also I did a few refactorings to get this:
directory exec "git status"
or
directory.execute("git", "commit", "-m", "A message")
I also opted to throw exceptions for error codes and shortened the wait, but that can easily be altered according to taste.
/**
* Shorthand for [File.execute]. Assumes that all spaces are argument separators,
* so no argument may contain a space.
* ```kotlin
* // Example
* directory exec "git status"
*
* // This fails since `'A` and `message'` will be considered as two arguments
* directory exec "git commit -m 'A message'"
* ```
*/
infix fun File.exec(command: String): String {
val arguments = command.split(' ').toTypedArray()
return execute(*arguments)
}
/**
* Executes command. Arguments may contain strings. More appropriate than [File.exec]
* when using dynamic arguments.
* ```kotlin
* // Example
* directory.execute("git", "commit", "-m", "A message")
* ```
*/
fun File.execute(vararg arguments: String): String {
val process = ProcessBuilder(*arguments)
.directory(this)
.start()
.also { it.waitFor(10, TimeUnit.SECONDS) }
if (process.exitValue() != 0) {
throw Exception(process.errorStream.bufferedReader().readText())
}
return process.inputStream.bufferedReader().readText()
}
As this is the first google result when searching for how to run commands in kotlin, I found my self struggeling to extend it to get basic standard input working, as the Pipe "|" is not supported for the ProcessBuilder. I've found out how to do it, and thought I'd share.
I've converted jkschneider's answer to be run as a simple function, now with optional stdin and output capturing.
It's a little less pretty, but more flexible.
You can run it like this:
exec("someCommandWithUserInput", stdIn = "yes")
/** Run a system-level command.
* Note: This is a system independent java exec (e.g. | doesn't work). For shell: prefix with "bash -c"
* Inputting the string in stdIn (if any), and returning stdout and stderr as a string. */
fun exec(cmd: String, stdIn: String = "", captureOutput:Boolean = false, workingDir: File = File(".")): String? {
try {
val process = ProcessBuilder(*cmd.split("\\s".toRegex()).toTypedArray())
.directory(workingDir)
.redirectOutput(if (captureOutput) ProcessBuilder.Redirect.PIPE else ProcessBuilder.Redirect.INHERIT)
.redirectError(if (captureOutput) ProcessBuilder.Redirect.PIPE else ProcessBuilder.Redirect.INHERIT)
.start().apply {
if (stdIn != "") {
outputStream.bufferedWriter().apply {
write(stdIn)
flush()
close()
}
}
waitFor(60, TimeUnit.SECONDS)
}
if (captureOutput) {
return process.inputStream.bufferedReader().readText()
}
} catch (e: IOException) {
e.printStackTrace()
}
return null
}
edit:
I've since had to use this so often I've made it into a little library: https://github.com/leonschreuder/kotlin-exec
Supports stdin, capturing stderr/stdout, understands (nested) quoted strings (" and ' and mixed) correctly etc, but this answer is obviously still valid too.
There is a kotlin library for easy run external command
Add this gradle dependency:
implementation("com.sealwu:kscript-tools:1.0.2")
And can run comamnd like this:
"cd ~ && ls".runCommand()
Output:
Applications Downloads MavenDep Pictures iOSProjects
Desktop IdeaProjects Movies Public scripts
Documents Library Music StudioProjects
Also you can get the output of command line by using evalBash
val date = "date".evalBash().getOrThrow() //execute shell command `date` and get the command's output and set the content to date variable
println(date) //This will print Fri Aug 19 21:59:56 CEST 2022 on console
val year = date.substringAfterLast(" ") // will get 2022 and assign to year
println(year)