34

我正在尝试spawn执行rm -rf node_modules后续操作npm install(在 Windows 7 上;n x 命令由透明安装的 CygWin 提供。所有n x 命令都可以在命令行上解析)。

我最初有这个 using exec,但想在它发生时捕获 stdout/stderr 信息,所以我想我会使用spawn,并重写代码以使用它。然而,这打破了一切。

重写后的rm命令变成了这样:

var spawn = require("child_process").spawn,
    child = spawn("rm", ["-rf", "node_modules"]);
child.stdout.on('data', function (data) { console.log(data.toString()); });
child.stderr.on('data', function (data) { console.log(data.toString()); });
child.on('error', function() { console.log(arguments); });

但是,运行它会产生以下错误:

rm: unknown option -- ,

Try `rm --help' for more information.

重写后的npm命令变成了这样:

var spawn = require("child_process").spawn,
    child = spawn("npm", ["install"]);
child.stdout.on('data', function (data) { console.log(data.toString()); });
child.stderr.on('data', function (data) { console.log(data.toString()); });
child.on('error', function() { console.log(arguments); });

但是,运行它会产生以下错误:

{
  '0': {
    [Error: spawn ENOENT]
    code: 'ENOENT',
    errno: 'ENOENT',
    syscall: 'spawn'
  }
}

如何让 spawn 运行与使用相同的命令,exec而不会在整个地方抛出错误?为什么这不起作用?阅读 API,http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options,似乎表明这正是人们应该如何使用 spawn...

4

3 回答 3

70

在尝试了很多不同的事情之后,我终于看到了 windows 上的“npm”实际上是什么,它原来是一个名为 bash 的脚本npm,以及一个名为的 windows-native 批处理脚本npm.cmd(不知道为什么它是 .cmd ,那应该是.bat,但你有它)。Windows 的命令解析器将看到npm,注意到它不是可执行文件,看到npm.cmd,然后注意到 IS 是可执行文件,然后将使用它。当您在终端中时,这很有帮助,但spawn()不会执行任何此类解决方案:传递它npm会使其失败,因为它不是可执行文件。npm.cmd但是,将其作为命令传递就可以了。

(另外,不知道为什么rm早先失败了,因为它实际上可以正常工作而没有我能说的任何更改。可能误读为问题的一部分,而实际上并非如此。)

所以:如果您spawn在 Windows 中遇到 ENOENT,当您尝试触发的命令在普通命令提示符下运行时,请确定您正在调用的命令是否是真正的可执行文件,或者该命令是否存在.bat/.cmd文件提示将为您“有用地”运行。如果是这样,请产生它。

编辑

由于这篇文章仍在获得支持,确保命令始终有效的一个好方法是基于 Windows 引导process.platformwin32

var npm = (process.platform === "win32" ? "npm.cmd" : "npm"),
    child = spawn(npm, ["install", ...]);
...

针对触发此错误的用例进行编辑

自从发布这个问题(及其答案)以来,已经发布了几个允许运行npm任务而不必依赖 exec 或 spawn 的包,您应该使用它们。

可能最受欢迎的是npm-run-all,它不仅可以让您npm从其他 npm 脚本以及 Node 运行任何任务,还可以添加命令以串行或并行运行多个 npm 脚本,使用或没有通配符。

在原始问题的上下文中,由于我试图npm作为 exec/spawn 运行以进行清理和重新安装,因此引发了错误,现代解决方案是在 package.json 中有一个专门的清理任务:

{
  ...
  "scripts": {
    "clean": "rimraf ./node_modules",
    ...
  },
  ...
}

然后调用该clean任务,然后在命令行上执行 install 命令

> npm run clean && npm install

或者,从一些 Node 脚本内部,使用:

const runAll = require("npm-run-all");
...
runAll(["clean", "install"])
    .then(() => {
        console.log("done!");
    })
    .catch(err => {
        console.log("failed!");
    });
于 2013-07-08T23:22:03.073 回答
-1

我认为这可能是某种 cygwin 陷阱。我正在运行 Ubuntu 12.04 并试图复制您的问题,但它对我来说效果很好。简而言之,我看不出你做错了什么。

如果它抱怨该选项,可能会将其拆分为多个选项,如下所示:

child = spawn("rm", ["-r", "-f", "node_modules"]);

这有点像万岁,但这也适用于我的 Ubuntu 12.04。您可能会尝试只删除一个文件,看看是否得到相同的结果。

child = spawn("rm", ["/home/username/Desktop/TestFile"]);

如果仍然失败,那么您知道您正在与一些疯狂的东西作斗争。

您甚至可以尝试只执行不带参数的命令,如下所示:

child = spawn("ls");

如果这仍然失败,那么我的猜测是你根本不可能让 spawn 工作,并且很感激至少 exec 正在工作。

对你来说答案不多,但就像我说的,我看不出你做错了什么。

此外,我看不到您的 npm 命令将如何工作,因为您没有指定要安装的内容,但话虽如此,如果我使用相同的命令,它的失败方式与我在这里看到的失败方式不同. . . 我看到很多 stderr 输出,而不是整体错误。

顺便说一句,我正在运行节点 v0.8.21。您可以通过 node -v 查询。如果您正在运行另一个版本,不妨试试 0.8.21。

于 2013-07-08T20:42:08.953 回答
-2

使用该过程的完整路径,例如:

var cmd = require('child_process').spawn("C:\\windows\\system32\\cmd.exe");
于 2015-03-09T10:39:21.023 回答