小智 215

我找到了一种特别简单的方法来了解其根本原因:

Error: spawn ENOENT
Run Code Online (Sandbox Code Playgroud)

这个错误的问题是,错误消息中几乎没有信息告诉你调用站点在哪里,即找不到哪个可执行文件/命令,特别是当你有一个很大的代码库,那里有大量的spawn调用.另一方面,如果我们知道导致错误的确切命令,那么我们可以按照@laconbass'回答来解决问题.

我找到了一种非常简单的方法来确定哪个命令导致问题,而不是像@laconbass'回答中建议的那样在代码中的任何地方添加事件监听器.关键的想法是使用包装器包装原始spawn调用,该包装器打印发送到spawn调用的参数.

这是包装函数,将它放在index.js服务器启动脚本的顶部或任何位置.

(function() {
    var childProcess = require("child_process");
    var oldSpawn = childProcess.spawn;
    function mySpawn() {
        console.log('spawn called');
        console.log(arguments);
        var result = oldSpawn.apply(this, arguments);
        return result;
    }
    childProcess.spawn = mySpawn;
})();
Run Code Online (Sandbox Code Playgroud)

然后,下次运行应用程序时,在未捕获的异常消息之前,您将看到类似的内容:

spawn called
{ '0': 'hg',
  '1': [],
  '2':
   { cwd: '/* omitted */',
     env: { IP: '0.0.0.0' },
     args: [] } }
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以轻松地知道实际执行了哪个命令,然后您可以找出为什么nodejs找不到可执行文件来解决问题.

  • 这是另一个想法:只需将“ spawn()”更改为“ exec()”,然后重试。exec()会告诉您_tried_要运行什么命令。 (3认同)
  • 我没有运气使用脚本。它根本不起作用。 (2认同)
  • 这对我来说非常有效。我只是将其放在gulpfile.js文件的顶部,然后使用bingo bango bongo,生成日志记录! (2认同)

lac*_*ass 110

第1步:确保spawn被称为正确的方式

首先,查看child_process.spawn(command,args,options)文档:

使用给定的command命令行参数启动一个新进程args.如果省略,则args默认为空数组.

第三个参数用于指定其他选项,默认为:

{ cwd: undefined, env: process.env }

使用env指定的环境变量,这将是新的过程可见,默认为process.env.

确保您没有输入任何命令行参数,command并且整个spawn调用有效.继续下一步.

第2步:确定发出错误事件的事件发射器

搜索每个调用的源代码spawn,或者child_process.spawn,即

spawn('some-command', [ '--help' ]);
Run Code Online (Sandbox Code Playgroud)

并在那里附加一个'error'事件的事件监听器,这样你就会注意到将它作为'Unhandled'抛出的确切事件发射器.调试后,可以删除该处理程序.

spawn('some-command', [ '--help' ])
  .on('error', function( err ){ throw err })
;
Run Code Online (Sandbox Code Playgroud)

执行,你应该得到你的'错误'监听器注册的文件路径和行号.就像是:

/file/that/registers/the/error/listener.js:29
      throw err;
            ^
Error: spawn ENOENT
    at errnoException (child_process.js:1000:11)
    at Process.ChildProcess._handle.onexit (child_process.js:791:34)
Run Code Online (Sandbox Code Playgroud)

如果前两行仍然是

events.js:72
        throw er; // Unhandled 'error' event
Run Code Online (Sandbox Code Playgroud)

再做这一步,直到他们不这样做.在继续下一步之前,您必须识别发出错误的侦听器.

第3步:确保$PATH已设置环境变量

有两种可能的情况:

  1. 您依赖于默认spawn行为,因此子进程环境将是相同的process.env.
  2. 您明确地传递一个env对象spawnoptions参数.

在这两种情况下,您都必须检查PATH生成的子进程将使用的环境对象上的键.

方案1的示例

// inspect the PATH key on process.env
console.log( process.env.PATH );
spawn('some-command', ['--help']);
Run Code Online (Sandbox Code Playgroud)

方案2的示例

var env = getEnvKeyValuePairsSomeHow();
// inspect the PATH key on the env object
console.log( env.PATH );
spawn('some-command', ['--help'], { env: env });
Run Code Online (Sandbox Code Playgroud)

缺少PATH(即,它undefined)将导致spawn发出ENOENT错误,因为command除非它是可执行文件的绝对路径,否则将无法找到任何错误.

如果PATH设置正确,请继续执行下一步.它应该是目录或目录列表.最后一种情况是通常的.

第4步:确保command存在于中定义的目录中PATH

ENOENT如果文件名command(即'some-command')在至少一个定义的目录中不存在,则Spawn可能会发出错误PATH.

找到确切的地方command.在大多数Linux发行版中,这可以通过which命令终端来完成.它将告诉您可执行文件的绝对路径(如上所述),或告诉您是否找不到它.

找到命令时的示例用法及其输出

> which some-command
some-command is /usr/bin/some-command
Run Code Online (Sandbox Code Playgroud)

未找到命令时的示例用法及其输出

> which some-command
bash: type: some-command: not found
Run Code Online (Sandbox Code Playgroud)

安装错误的程序是找不到命令的最常见原因.如果需要,请参阅每个命令文档并进行安装.

当命令是一个简单的脚本文件时,确保它可以从一个目录访问PATH.如果不是,请将其移至一个或链接到它.

一旦确定PATH已正确设置command并可从中访问,您应该能够在不spawn ENOENT抛出的情况下生成子进程.

  • 我还发现,如果在选项中指定`cwd`,则会抛出ENOENT,但给定的目录不存在. (31认同)
  • @DanielImfeld TOTAL SAVIOR.你应该写一个说这个的答案. (4认同)
  • 当你使用`spawn('some-command',[' - help'],{env:env});`作为这个答案的第3步所示并且正在传递一个自定义环境时,一定要指定` PATH`,例如:`{env:{PATH:process.env.PATH}}`.默认情况下,env选项不会从当前的env继承变量. (2认同)
  • 我可以通过将`shell:true`传递给派生选项来解决我的问题。 (2认同)

Lee*_*run 31

正如@DanielImfeld指出的那样,如果在选项中指定"cwd",则会抛出ENOENT,但给定的目录不存在.


ash*_*deh 27

在 Windows 中,只需添加shell: true选项即可解决我的问题:

不正确:

const { spawn } = require('child_process');
const child = spawn('dir');
Run Code Online (Sandbox Code Playgroud)

正确的:

const { spawn } = require('child_process');
const child = spawn('dir', [], {shell: true});
Run Code Online (Sandbox Code Playgroud)

  • 请注意,(https://nodejs.org/api/child_process.html#child_processspawncommand-args-options)“如果启用了 shell 选项,请勿将未经消毒的用户输入传递给此函数。任何包含 shell 元字符的输入都可能会被用于触发任意命令执行。” (3认同)
  • 谢谢!这解决了我的问题,无需定义 cmd 或路径 (2认同)

Nil*_*zor 26

Windows解决方案:替换spawnnode-cross-spawn.例如,在app.js的开头就像这样:

(function() {
    var childProcess = require("child_process");
    childProcess.spawn = require('cross-spawn');
})(); 
Run Code Online (Sandbox Code Playgroud)

  • 工作,除了它是一个drop-in,不需要child_process。与节点的 spawn 或 spawnSync 完全相同,因此它是替代品。`var spawn = require('cross-spawn');` `// 异步生成 NPM var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: '继承' });` (3认同)

Ale*_*lls 26

@ laconbass的回答对我有帮助,可能是最正确的.

我来到这里是因为我错误地使用了spawn.举个简单的例子:

这是不正确的:

const s = cp.spawn('npm install -D suman', [], {
    cwd: root
});
Run Code Online (Sandbox Code Playgroud)

这是不正确的:

const s = cp.spawn('npm', ['install -D suman'], {
    cwd: root
});
Run Code Online (Sandbox Code Playgroud)

这是对的:

const s = cp.spawn('npm', ['install','-D','suman'], {
    cwd: root
});
Run Code Online (Sandbox Code Playgroud)

但是,我建议这样做:

const s = cp.spawn('bash');
s.stdin.end(`cd "${root}" && npm install -D suman`);
s.once('exit', code => {
   // exit
});
Run Code Online (Sandbox Code Playgroud)

这是因为cp.on('exit', fn)只要安装了bash,事件就会一直触发,否则cp.on('error', fn),如果我们直接启动'npm',如果我们以第一种方式使用它,事件可能会先触发.

  • 喜欢这个答案的每个人也可能对这个原生替代品感兴趣:https://gist.github.com/ORESoftware/7bf225f0045b4649de6848f1ea5def4c (2认同)
  • 被否决是因为如果你想要一个 shell,那么你应该使用 `child_process.exec` 或将 `shell: true` 传递给 `spawn`。 (2认同)

Li *_*eng 18

对于Windows上的ENOENT,https://github.com/nodejs/node-v0.x-archive/issues/2318#issuecomment-249355505修复它.

例如,用以下代码替换spawn('npm',[' - v'],{stdio:'inherit'}):

  • 关键部分是添加`shell:true` (5认同)
  • 在哪里进行这些修改? (2认同)

Ale*_*pin 17

对于任何可能偶然发现这一点的人来说,如果所有其他答案都没有用,并且你在Windows上,那么就知道Windows和环境变量目前存在一个大问题spawnPATHEXT,可能会导致某些调用产生不起作用,具体取决于方式目标命令已安装.

  • 使用node-cross-spawn为我工作.请参阅以下答案:http://stackoverflow.com/a/35561971/507339 (5认同)
  • 什么是解决方案? (2认同)
  • 花了很长时间试图找出问题所在,结果这就是问题所在。我放弃了`spawn`,而是使用了`exec`。 (2认同)

lac*_*ass 17

如何研究引发错误的 spawn 调用:

已知的常见原因

  1. 环境问题

    • 系统中不存在该命令可执行文件(未安装依赖项)。prominc 的回答
    • 命令可执行文件不存在于由PATH环境变量指定的目录中。
  2. 仅限 Windows 的错误/怪癖

  3. 错误spawn('command', ['--argument', 'list'], { cwd, env, ...opts })用法

    • 指定的工作目录 ( opts.cwd) 不存在 ·leeroy-brun 的回答
    • 命令中的参数列表 String spawn('command --wrong --argument list')
    • 命令字符串中的环境变量 spawn('ENV_VAR=WRONG command')
    • 参数列表Array指定为String spawn('cmd', '--argument list')
    • 取消设置环境PATH变量spawn('cmd', [], { env: { variable } }=>spawn('cmd', [], { env: { ...process.env, variable } }

有 2 个可能的起源ENOENT

  1. 您正在编写的代码
  2. 你依赖的代码

当来源是您依赖的代码时,通常的原因是环境问题(或 Windows 怪癖)



Ins*_*sOp 9

在任何人花费大量时间调试此问题之前,大多数情况下可以通过删除node_modules和重新安装软件包来解决。

安装:

如果存在锁定文件,您可能会使用

yarn install --frozen-lockfile
Run Code Online (Sandbox Code Playgroud)

或者

npm ci
Run Code Online (Sandbox Code Playgroud)

分别。如果不是那么

yarn install
Run Code Online (Sandbox Code Playgroud)

或者

npm i
Run Code Online (Sandbox Code Playgroud)


Pro*_*Inc 7

在我的情况下,由于没有安装必要的依赖系统资源,我得到了这个错误.

更具体地说,我有一个使用ImageMagick的NodeJS应用程序.尽管安装了npm软件包,但未安装核心Linux ImageMagick.我做了一个apt-get来安装ImageMagick,之后一切都很棒!


Ric*_*ler 6

你在改变env选项吗?

然后看看这个答案。


我试图生成一个节点进程和 TIL,你应该在生成时传播现有的环境变量,否则你会丢失PATH环境变量和其他可能的重要变量。

这对我来说是修复:

const nodeProcess = spawn('node', ['--help'], {
  env: {
    // by default, spawn uses `process.env` for the value of `env`
    // you can _add_ to this behavior, by spreading `process.env`
    ...process.env,
    OTHER_ENV_VARIABLE: 'test',
  }
});
Run Code Online (Sandbox Code Playgroud)


Kar*_*ter 6

如果您在无法修改其源的应用程序中遇到此问题,请考虑将环境变量设置NODE_DEBUGchild_process,例如 来调用它NODE_DEBUG=child_process yarn test。这将为您提供在哪个目录中调用了哪些命令行的信息,并且通常最后的详细信息是失败的原因。