因此,我试图从linux获取电池状态,到目前为止,第一个命令(路径变量)完美返回,并且我能够从输入流中以Sequence的形式获取其响应,但不幸的是,第二个命令(结果是变量)返回空序列。
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
取自here
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
}
这里的问题是管道。
您正在尝试运行管道-一种涉及运行多个程序的构造,需要外壳程序才能解释。
但是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实例,然后可以运行您的管道;参见this answer。
但是在您自己的代码中进行过滤,并且避免完全调用grep
,可能会更简单,更安全,更高效。
我建议捕获过程的错误输出,这很可能使问题清楚了。