我正在为用Kotlin / Native编写的命令行工具进行概念验证,因为它似乎是跨平台二进制文件的理想语言和运行时。
此命令行工具需要与os用户$ PATH或shell环境中的操作系统可执行文件,命令和/或shell函数进行定期交互。但是,我在kotlin-native samples或文档中看不到任何可能表明如何进行操作的示例:
在JVM领域,我们将全部使用java.lang.ProcessBuilder
,但这显然在Kotlin / Native中不可用。
我发现了cinterop / posix platform.posix.system
函数,但这不能让您访问进程的流。
在我的网络研究中,我发现一个非常不错的C tutorial,表明执行此操作的唯一干净方法是使用fork
和dup2
等,但是我不清楚是否或将如何转换为Kotlin /本机代码。
答案 0 :(得分:1)
我使用 kotlin native 进行了一些尝试,并成功为 jvm、mac、unix 和(未经测试的)windows 执行了 posix exec 命令...
impossible to detect the standard
目标共同
fun String.executeCommand(
redirectStderr: Boolean = true
): String? = MppProcess.executeCommand(this, redirectStderr)
interface IMppProcess {
fun executeCommand(
command: String,
redirectStderr: Boolean = true
): String?
}
expect object MppProcess : IMppProcess {
override fun executeCommand(
command: String,
redirectStderr: Boolean
): String?
}
目标 jvm
actual object MppProcess : IMppProcess {
actual override fun executeCommand(
command: String,
redirectStderr: Boolean
): String? {
return runCatching {
ProcessBuilder(command.split(Regex("(?<!(\"|').{0,255}) | (?!.*\\1.*)")))
//.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.apply { if (redirectStderr) this.redirectError(ProcessBuilder.Redirect.PIPE) }
.start().apply { waitFor(60L, TimeUnit.SECONDS) }
.inputStream.bufferedReader().readText()
}.onFailure { it.printStackTrace() }.getOrNull()
}
}
目标 mac/unix/windows
import kotlinx.cinterop.refTo
import kotlinx.cinterop.toKString
import platform.posix.fgets
import platform.posix.pclose
import platform.posix.popen
actual object MppProcess : IMppProcess {
actual override fun executeCommand(
command: String,
redirectStderr: Boolean
): String? {
val commandToExecute = if (redirectStderr) "$command 2>&1" else command
val fp = popen(commandToExecute, "r") ?: error("Failed to run command: $command")
val stdout = buildString {
val buffer = ByteArray(4096)
while (true) {
val input = fgets(buffer.refTo(0), buffer.size, fp) ?: break
append(input.toKString())
}
}
val status = pclose(fp)
if (status != 0) {
error("Command `$command` failed with status $status${if (redirectStderr) ": $stdout" else ""}")
}
return stdout
}
}
现在只执行了 ls,但它有效。