使用 nodejs 的 spawn 会导致“unknown option --”和“[Error: spawn ENOENT]”错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17516772/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:58:23  来源:igfitidea点击:

Using nodejs's spawn causes "unknown option -- " and "[Error: spawn ENOENT]" errors

node.jsexecspawn

提问by Mike 'Pomax' Kamermans

I'm trying to get spawnto effect an rm -rf node_modulesfollowed by npm install(on windows 7; nx commands courtesy of a transparently installed CygWin. All nx commands resolve on a commandline just fine).

我正在尝试spawn实现rm -rf node_modules后跟npm install(在 Windows 7 上;nx 命令由透明安装的 CygWin 提供。所有nx 命令都可以在命令行上解析就好了)。

I initially had this using exec, but wanted to catch the stdout/stderr information as it occurred, so I figured I'd use spawn, and rewrote the code to use that. However, that breaks everything.

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

The rmcommand, rewritten, became this:

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); });

However, running this generates the following error:

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

rm: unknown option -- ,

Try `rm --help' for more information.

The npmcommand, rewritten, became this:

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); });

However, running this generates the following error:

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

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

How do I make spawn run the same commands that worked fine using execwithout it throwing up errors all over the place? And why does this not work? Reading the API, http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options, seems to suggest this is precisely how one is supposed to use spawn...

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

回答by Mike 'Pomax' Kamermans

After lots of trying different things, I finally had a look at what "npm" actually is on windows, and it turns out to be a bash script called npm, as well as a windows-native batch script called npm.cmd(no idea why it's .cmd, that should be .bat, but there you have it). Windows's command resolver will see npm, notice that it's not an executable, see npm.cmd, and then notice that IS an executable, and will then use that instead. This is helpful when you're in a terminal, but spawn()will not do any such resolution: passing it npmwill make it fail because it's not an executable. Passing it npm.cmdas command, however, works just fine.

经过大量的尝试不同的东西,我终于看了一下什么是“故宫”,实际上是在Windows上,它原来是叫bash脚本npm,以及称为Windows的本地批处理脚本npm.cmd(不知道为什么它的.CMD ,那应该是 .bat,但你有它)。Windows 的命令解析器将看到npm,注意它不是可执行文件,看到npm.cmd,然后注意是可执行文件,然后将使用它。当您在终端中时,这很有用,但spawn()不会执行任何此类解析:传递它npm会使其失败,因为它不是可执行文件。npm.cmd然而,将它作为命令传递,效果很好。

(Also, not sure why rmwas failing earlier, since that actually works correctly without any changes that I can tell. Probably misread that as part of the problem when in fact it wasn't.)

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

So: if you run into spawnsaying ENOENT in windows, when the command you're trying to trigger works in a plain command prompt, find out if the command you're calling is a true executable, or whether there's a .bat/.cmdfile that the command prompt will "helpfully" run for you instead. If so, spawn that.

所以:如果你spawn在 Windows 中遇到说 ENOENT,当你试图触发的命令在普通命令提示符下工作时,找出你正在调用的命令是否是一个真正的可执行文件,或者是否有一个.bat/.cmd文件,该命令提示将“帮助”为您运行。如果是这样,产生那个。

edit

编辑

since this post is still getting upvotes, a good way to ensure the command always works is to bootstrap it based on process.platform, which will be win32for windows.

由于这篇文章仍在获得赞成票,确保该命令始终有效的一个好方法是基于 引导它process.platform,这将win32用于 Windows。

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

edit specific to the use-casethat triggered this error

特定于触发此错误的用例的编辑

since posting this question (and its answer), several packages have been released that allow running npmtasks without having to rely on exec or spawn, and you should use them instead.

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

Probably the most popular is npm-run-allwhich doesn't just give you the power to run any npmtask from other npm scripts as well as from Node, but also adds commands to run multiple npm scripts in series or in parallel, with or without wildcards.

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

In the context of the original question, where the error got thrown because I was trying to run npmas an exec/spawn in order to effect a cleanup and reinstall, the modern solution is to have a dedicated cleaning task in package.json:

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

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

And to then invoke that cleantask followed by the install command on the command line as

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

> npm run clean && npm install

Or, from inside some Node script, using:

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

const runAll = require("npm-run-all");
...
runAll(["clean", "install"])
    .then(() => {
        console.log("done!");
    })
    .catch(err => {
        console.log("failed!");
    });

回答by Brian

I think this may be some sort of cygwin gotcha. I'm running Ubuntu 12.04 and tried to duplicate your problem, but it works just fine for me. In short, I don't see anything you are doing wrong.

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

If it is complaining about the option, maybe split it up into multiple options like so:

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

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

That's kind of a hail mary, but that works on my Ubuntu 12.04 as well. You might try to just delete a single file and see if you get the same thing.

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

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

If that still fails, then you know you are working against some crazy stuff.

如果这仍然失败,那么你知道你正在对抗一些疯狂的东西。

You could even try to just execute a command with no parameters like so:

您甚至可以尝试只执行一个没有参数的命令,如下所示:

child = spawn("ls");

If that still fails, you aren't likely to get spawn to work at all would be my guess and be grateful that at least exec is working.

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

Not much in the realm of answers for you, but like I said, I can't see anything you are doing incorrectly.

为您提供答案的范围并不多,但就像我说的那样,我看不出您做错了什么。

Furthermore, I don't see how your npm command is going to work because you aren't specifying what to install, but that being said, it fails in a different way than I'm seeing it fail here if I use the same command. . . I see lots of stderr output, not an overall error.

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

BTW, I'm running node v0.8.21. You can query that by node -v. If you are running another version, maybe give 0.8.21 a try.

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

回答by Brian

Use full path for the process, like:

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

var cmd = require('child_process').spawn("C:\windows\system32\cmd.exe");