解决 ProcessBuilder 无法执行 NPM 及其他 node 全局命令的问题

395 阅读1分钟

描述

windows下使用ProcessBuilder(JDK 自带)执行系统命令行npm -v时报错:

Cannot run program "npm" (in directory "."): CreateProcess error=2, 系统找不到指定的文件

通过 CMD(命令行提示符)是能够正常执行的,而且代码在linux以及macOS下可以正常运行,这就有点奇怪了🤣

代码如下:

fun runCmd(
    cmd: List<String>,
    workDir: File = File("."),
    timeoutAmount: Long = 30L,
    timeUnit: TimeUnit = TimeUnit.SECONDS
):Pair<Int, String?> =
    try {
        val pb = ProcessBuilder(cmd)
            .directory(workDir)
            .redirectErrorStream(true)
            .start()

        // jdk17之后这样写
        val text = pb.also {  it.waitFor(timeoutAmount, timeUnit) }.inputReader().readText()

        Pair(pb.exitValue(), text.trim())
    } catch (e: Exception) {
        Pair(-1, e.message)
    }

fun main() {
    val npmReult = runCmd(listOf("npm", "-v"))
    println("[CODE=${npmReult.first}] ${npmReult.second}")
}

原因

归根结底,就是 OS 在现有 path 没有找到可执行程序npm.exe,我们可以看下 windows 系统的 node 全局目录,存在npmnpm.cmd两个文件,至此真相大白,原来在 windows 下需要用 npm.cmd 🙃

整改方案

fun main() {
    val cmd = if(System.getProperty("os.name").uppercase().contains("WINDOW")) "npm.cmd" else "npm"
    val npmReult = runCmd(listOf(cmd, "-v"))
    println("[CODE=${npmReult.first}] ${npmReult.second}")
}

此方法同样适用于通过npm i -g安装的全局工具。