Java/Kotlin 将命令输出重定向到标准输出和字符串的方法
Java/Kotlin way to redirect command output to both stdout and String
我正在将代码从 NodeJS 服务器转换到 Kotlin Ktor 服务器。
NodeJS 代码将输出拆分为要由代码处理的字符串和实时服务器日志记录:
const shellScript = exec("./myScript.sh",
(error, stdout, stderr) => {
// this happens when the script ends
// stdout and stderr contain full script output
if (error === null) {
...
}
});
// Realtime server logging
shellScript.stdout.on('data', (data) => { console.log(data); });
shellScript.stderr.on('data', (data) => { console.error(data); });
根据我对java.lang.ProcessBuilder
的理解,我们需要生成一个线程(或协程)来循环轮询 inputStream 和 errorStream,并将它们累积在一个 volatile 字段中。
有更简洁的方法吗?
这是我最初想避免的 ProcessBuilder 解决方案。尽管体积庞大,但它可以完成工作。如果有更好的 API 可用,请告诉我!
var logs:String = ""
runCatching {
var command:List<String> = listOf("command", "arg")
parameters.params?.let {command += it} // dynamic args
ProcessBuilder(command)
.directory(File(scriptRoot))
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectErrorStream(true) // Merges stderr into stdout
.start().also { process ->
withContext(Dispatchers.IO) { // More info on this context switching : https://elizarov.medium.com/blocking-threads-suspending-coroutines-d33e11bf4761
launch {
process.inputStream.bufferedReader().run {
while (true) { // Breaks when readLine returns null
readLine()?.let { line ->
logger.trace(line) // realtime logging
logs += "$line\n" // record
} ?: break
}
}
}
process.waitFor(60, TimeUnit.MINUTES)
if(process.isAlive) {
logs += "TIMEOUT occurred".also { logger.warn(it) } + "\n"
process.destroy()
}
}
}
}.onSuccess { process ->
if(process.exitValue() == 0) {
// completed with success
} else {
// completed with failure
}
}.onFailure { ex ->
logs = ex.stackTraceToString()
}
// Logs are available in $logs
我正在将代码从 NodeJS 服务器转换到 Kotlin Ktor 服务器。
NodeJS 代码将输出拆分为要由代码处理的字符串和实时服务器日志记录:
const shellScript = exec("./myScript.sh",
(error, stdout, stderr) => {
// this happens when the script ends
// stdout and stderr contain full script output
if (error === null) {
...
}
});
// Realtime server logging
shellScript.stdout.on('data', (data) => { console.log(data); });
shellScript.stderr.on('data', (data) => { console.error(data); });
根据我对java.lang.ProcessBuilder
的理解,我们需要生成一个线程(或协程)来循环轮询 inputStream 和 errorStream,并将它们累积在一个 volatile 字段中。
有更简洁的方法吗?
这是我最初想避免的 ProcessBuilder 解决方案。尽管体积庞大,但它可以完成工作。如果有更好的 API 可用,请告诉我!
var logs:String = ""
runCatching {
var command:List<String> = listOf("command", "arg")
parameters.params?.let {command += it} // dynamic args
ProcessBuilder(command)
.directory(File(scriptRoot))
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectErrorStream(true) // Merges stderr into stdout
.start().also { process ->
withContext(Dispatchers.IO) { // More info on this context switching : https://elizarov.medium.com/blocking-threads-suspending-coroutines-d33e11bf4761
launch {
process.inputStream.bufferedReader().run {
while (true) { // Breaks when readLine returns null
readLine()?.let { line ->
logger.trace(line) // realtime logging
logs += "$line\n" // record
} ?: break
}
}
}
process.waitFor(60, TimeUnit.MINUTES)
if(process.isAlive) {
logs += "TIMEOUT occurred".also { logger.warn(it) } + "\n"
process.destroy()
}
}
}
}.onSuccess { process ->
if(process.exitValue() == 0) {
// completed with success
} else {
// completed with failure
}
}.onFailure { ex ->
logs = ex.stackTraceToString()
}
// Logs are available in $logs