首页 > 解决方案 > 在某些特定情况下没有从 ProcessBuilder 的输入流中得到响应

问题描述

所以我试图从linux获取电池状态,到目前为止第一个命令(路径变量)完美返回,我能够从输入流中以序列的形式获得它的响应,但不幸的是第二个命令(结果变量)返回空序列。

fun getLinuxBatteryStatus(): Nothing? {
    val path = """upower --enumerate""".runCommand() ?: return null

    val parameters = listOf("present", "state", "energy-full", "energy", "energy-rate", "time to empty", "percentage")
    val result = """upower -i ${path.first { "battery_BAT" in it }} | grep -E "${parameters.joinToString("|")}""""
        .also { println(it) }
        .runCommand() ?: return null

    result.forEach(::println)   // <- no ouput
    // println(result.count())  // <- 0

    /* Do other thing and return something (that is not related to problem) */
}

输出:

upower -i /org/freedesktop/UPower/devices/battery_BAT1 | grep -E "present|state|energy-full|energy|energy-rate|time to empty|percentage"

上面的输出来自also上一条命令中的块,只是为了预览命令的字符串以进行调试。如果我将上述命令直接运行到终端中,我将成功获得如下响应:

    present:             yes
    state:               charging
    energy:              47.903 Wh
    energy-empty:        0 Wh
    energy-full:         50.299 Wh
    energy-full-design:  48.004 Wh
    energy-rate:         17.764 W
    percentage:          95%

为什么 ProcessBuilder 的最后一个命令不起作用(不返回任何响应)?

注意:扩展功能runCommand取自这里

private fun String.runCommand(
    workingDir: File = File("."),
    timeoutAmount: Long = 60,
    timeoutUnit: TimeUnit = TimeUnit.SECONDS
): Sequence<String>? = try {
    ProcessBuilder(split("\\s".toRegex()))
        .directory(workingDir)
        .redirectOutput(ProcessBuilder.Redirect.PIPE)
        .redirectError(ProcessBuilder.Redirect.PIPE)
        .start()
        .apply { waitFor(timeoutAmount, timeoutUnit) }
        .inputStream.bufferedReader().lineSequence()
} catch (e: IOException) {
    e.printStackTrace()
    null
}

标签: linuxkotlinprocessbuilderbattery

解决方案


这里的问题是管道。

你正在尝试运行一个管道——一个涉及运行多个程序的结构,需要一个 shell 来解释。

但是ProcessBuilder运行一个程序。在这种情况下,它正在运行程序 upower并向其传递参数-i/org/freedesktop/UPower/devices/battery_BAT1|grep-E"present|state|energy-full|energy|energy-rate|time to empty|percentage"。显然upower不知道如何处理|参数或其后面的参数。

你可以ProcessBuilder用来运行一个 shell 实例,然后它可以运行你的管道;看到这个答案

但是在您自己的代码中进行过滤并完全避免调用可能会更简单、更安全、更有效grep

我建议捕获进程的错误输出,这很可能会使问题变得清晰。


推荐阅读