如何在node.js上调试“Error:spawn enoint”?

2024-04-19 03:57:12 发布

您现在位置:Python中文网/ 问答频道 /正文

3条回答

步骤1:确保spawn被正确调用

首先,查看docs for child_process.spawn( command, args, options )

Launches a new process with the given command, with command line arguments in args. If omitted, args defaults to an empty Array.

The third argument is used to specify additional options, which defaults to:

{ cwd: undefined, env: process.env }

Use env to specify environment variables that will be visible to the new process, the default is process.env.

确保没有在command中放入任何命令行参数,并且整个spawn调用是有效的。继续下一步。

步骤2:识别发出错误事件的事件发射器

在源代码中搜索每次调用spawn,或child_process.spawn,即

spawn('some-command', [ '--help' ]);

并为“error”事件附加一个事件侦听器,这样您就会注意到将其作为“Unhandled”抛出的确切事件发射器。调试之后,可以删除该处理程序。

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

执行时,您应该获得注册“error”侦听器的文件路径和行号。类似于:

/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)

如果前两行仍然是

events.js:72
        throw er; // Unhandled 'error' event

再重复这一步,直到他们没有。在执行下一步之前,必须确定发出错误的侦听器。

步骤3:确保设置了环境变量$PATH

有两种可能的情况:

  1. 您依赖于默认的spawn行为,因此子进程环境将与process.env相同。
  2. 您是在向options参数的spawn传递env对象。

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

场景1的示例

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

场景2的示例

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

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

正确设置PATH后,继续下一步。它应该是一个目录或目录列表。最后一个病例是常见的。

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

如果文件名command(即“某些命令”)不存在于PATH上定义的至少一个目录中,则生成可能会发出ENOENT错误。

找到command的确切位置。在大多数linux发行版上,这可以通过which命令从终端完成。它将告诉您可执行文件的绝对路径(如上所述),或者告诉您是否未找到它。

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

> which some-command
some-command is /usr/bin/some-command

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

> which some-command
bash: type: some-command: not found

未安装程序是导致未找到命令的最常见原因。如果需要,请参阅每个命令文档并安装它。

当命令是一个简单的脚本文件时,请确保可以从PATH上的目录访问它。如果不能,请将其移动到一个目录或建立指向该目录的链接。

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

注意:这个错误几乎总是因为命令不存在,因为工作目录不存在,或者是因为一个仅限windows的错误而导致的。

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

Error: spawn ENOENT

这个错误的问题是,错误消息中很少有信息告诉您调用位置在哪里,即找不到哪个可执行文件/命令,特别是当您有大量派生调用的大型代码库时。另一方面,如果我们知道导致错误的确切命令,那么我们可以按照@laconbass' answer来解决问题。

我找到了一种很容易发现哪个命令导致了问题的方法,而不是像@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;
})();

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

spawn called
{ '0': 'hg',
  '1': [],
  '2':
   { cwd: '/* omitted */',
     env: { IP: '0.0.0.0' },
     args: [] } }

通过这种方式,您可以很容易地知道实际执行的是哪个命令,然后您就可以了解nodejs为什么找不到可执行文件来解决这个问题。

作为@DanielImfeld pointed it,如果在选项中指定“cwd”,则将抛出enoint,但给定的目录不存在。

相关问题 更多 >