为啥 __dirname 没有在节点 REPL 中定义?

Posted

技术标签:

【中文标题】为啥 __dirname 没有在节点 REPL 中定义?【英文标题】:Why is __dirname not defined in node REPL?为什么 __dirname 没有在节点 REPL 中定义? 【发布时间】:2012-02-07 16:47:45 【问题描述】:

从节点手册中我看到我可以使用__dirname 获取文件的目录,但是从 REPL 中这似乎是未定义的。这是我的误解还是错误在哪里?

$ node
> console.log(__dirname)
ReferenceError: __dirname is not defined
    at repl:1:14
    at REPLServer.eval (repl.js:80:21)
    at Interface.<anonymous> (repl.js:182:12)
    at Interface.emit (events.js:67:17)
    at Interface._onLine (readline.js:162:10)
    at Interface._line (readline.js:426:8)
    at Interface._ttyWrite (readline.js:603:14)
    at ReadStream.<anonymous> (readline.js:82:12)
    at ReadStream.emit (events.js:88:20)
    at ReadStream._emitKey (tty.js:320:10)

【问题讨论】:

__dirname__filename 也是 not available when node is called with the --experimental-modules flag。 我在使用 eslint 时遇到了这个问题,我在 .eslintrc.json 文件中错误地设置了 "browser": true 而不是 "node": true 如果这里没有任何效果,那就是 hack ***.com/a/49879107/696535 【参考方案1】:

__dirname 仅在脚本中定义。它在 REPL 中不可用。

尝试编写脚本a.js

console.log(__dirname);

并运行它:

node a.js

你会看到__dirname被打印出来。

添加背景说明:__dirname 表示“此脚本的目录”。在 REPL 中,您没有脚本。因此,__dirname 没有任何实际意义。

【讨论】:

另外你不能在 RequireJS 模块中使用一些全局变量。如果你在服务器端使用 RequireJS,请参阅***.com/questions/9027429/…。 是的,这真的应该添加到答案中,因为这就是我的目标。 不将其添加到 REPL 的加载脚本中是令人讨厌的。我想不出它不存在的任何原因...... 我在 REPL 中使用 .load script.js 加载了一个脚本文件。太糟糕了 __dirname 在 script.js 中仍然不可用 点赞!当我想知道 wtf 正在发生时,为我节省了 15 分钟【参考方案2】:

在现有答案的基础上,您可以在 REPL 中定义它:

__dirname = path.resolve(path.dirname(''));

或者:

__dirname = path.resolve();

If no path segments are passed, path.resolve() will return the absolute path of the current working directory.


或@Jthorpe 的替代方案:

__dirname = process.cwd();
__dirname = fs.realpathSync('.');
__dirname = process.env.PWD

【讨论】:

如果您使用nesh,您可以将其定义为加载脚本的一部分;这很漂亮 __dirname = process.cwd()__dirname=fs.realpathSync('.')__dirname = process.env.PWD path.dirname 在最新的主要版本6.0.0 中似乎不再接受非字符串值,因此此答案中的第一个建议将不起作用。【参考方案3】:

如果您使用的是Node.js modules,则__dirname__filename 不存在。

来自Node.js documentation:

没有 require、exports、module.exports、__filename、__dirname

这些 CommonJS 变量在 ES 模块中不可用。

require 可以使用module.createRequire() 导入到 ES 模块中。

__filename__dirname 的等价物可以通过 import.meta.url 在每个文件中创建:

import  fileURLToPath  from 'url';
import  dirname  from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

https://nodejs.org/docs/latest-v15.x/api/esm.html#esm_no_filename_or_dirname

【讨论】:

从技术上讲,这是这里唯一正确的答案。所有其他解决方案都使用当前工作目录。这与 __dirname 功能不同,后者实际上是保存当前正在运行的脚本的文件夹。 这是这个确切问题的完美答案。谢谢,对我帮助很大! @RaviLuthra 100% 正确。 同意这是这里唯一正确的答案“如果”问题与 ES6 模块类型的架构有关。导入语句需要引用最终传递给 __dirname 的路径,该路径实际上是保存当前正在运行的脚本的文件夹。 ——【参考方案4】:

在 ES6 中使用:

import path from 'path';
const __dirname = path.resolve();

在使用--experimental-modules调用节点时也可用

【讨论】:

REPL中不需要导入核心模块;它会为您即时加载它们。 这给出了当前工作目录,而不是当前.js文件的目录。 @Dirbaio,当您在 REPL 中时,当前的 .js 文件会是什么? @c24w 刚查了一下,好像给了CWD 这是错误的。 __dirname 是当前模块目录,但您的解决方案使其成为当前工作目录。这个废话是怎么得到这么多赞成的,我无法理解。【参考方案5】:

正如@qiao 所说,您不能在节点repl 中使用__dirname。但是,如果您需要在控制台中使用此值,则可以使用path.resolve()path.dirname()。虽然,path.dirname() 只会给你一个“。”所以,可能没有那么有帮助。请务必require('path')

【讨论】:

【参考方案6】:

我也尝试使用 path.join(__dirname, 'access.log') 加入我的路径,但它抛出了同样的错误。

这是我修复它的方法:

我首先导入了path包并声明了一个名为__dirname的变量,然后调用了resolvepath方法。

在 CommonJS 中

var path = require("path");

var __dirname = path.resolve();

在 ES6+ 中

import path  from 'path';

const __dirname = path.resolve();

编码愉快.......

【讨论】:

我在节点 v15.3.0 上,不需要使用 path.resolve()__dirname 开箱即用。你的答案仍然与 ES6+ 相关吗? @Zac __dirname 仅在使用 CommonJS 的 Node 14 或更高版本上可用。但是 ECMA 正在推动 ES 模块成为标准而不是 CommonJS。【参考方案7】:

-> 在 ES6 版本中使用:

import path from "path"
const __dirname = path.resolve();

-> 并像这样使用它,例如:

res.sendFile(path.join(__dirname ,'views','shop.html'))

【讨论】:

等同于__dirname,而是process.cwd()。例如,从不同目录运行脚本时会得到不同的结果。使用 ESM 时,更好的方法是使用 import.meta.url。见nodejs.org/docs/latest-v14.x/api/esm.html#esm_import_meta 和***.com/questions/46745014/…【参考方案8】:

如果你有node __dirname not definednode --experimental-modules,你可以这样做:

const __dirname = path.dirname(import.meta.url)
                      .replace(/^file:\/\/\//, '') // can be usefull

因为其他示例,只使用当前/pwd 目录而不是其他目录。

【讨论】:

【参考方案9】:

看来你也可以这样做:

__dirname=fs.realpathSync('.');

当然,别忘了fs=require('fs')

(它在节点脚本中并不是真正的全局,它只是在模块级别定义)

【讨论】:

你不需要 REPL 中的核心模块;它会为您即时加载它们。【参考方案10】:

我以 SYSTEM 用户身份从批处理文件运行脚本,所有变量(如 process.cwd()path.resolve() 和所有其他方法都会为我提供 C:\Windows\System32 文件夹的路径,而不是实际路径。在实验期间,我注意到当抛出错误时,堆栈包含节点文件的真实路径。

这是一种通过触发错误并从 e.stack 中提取路径来获取真实路径的非常老套的方法。不要使用。

// this should be the name of currently executed file
const currentFilename = 'index.js';

function veryHackyGetFolder() 
  try 
    throw new Error();
   catch(e) 
    const fullMsg = e.stack.toString();
    const beginning = fullMsg.indexOf('file:///') + 8;
    const end = fullMsg.indexOf('\/' + currentFilename);
    const dir = fullMsg.substr(beginning, end - beginning).replace(/\//g, '\\');
    return dir;
  

用法

const dir = veryHackyGetFolder();

【讨论】:

如果你不是通过 REPL 运行它,你可以使用__dirname__filename 这是至少试图提供正确解决方案的唯一答案。 @c24w 我尝试了 __dirname、__filename 和其他所有内容。在我的情况下,没有标准解决方案有效。如果您对 github.com/DVLP/Unscheduler 感到无聊,这是我的项目,它从任务调度程序以 SYSTEM 身份运行进程。任何其他可行的标准解决方案显然都比我上面的 hack 更好:)【参考方案11】:

虽然它不是这个问题的解决方案,但我想添加它,因为它可以帮助其他人。

您应该在 dirname 之前有 两个下划线不是一个下划线__dirname 不是 _dirname)。

NodeJS Docs

【讨论】:

__dirname(带两个下划线)在 REPL 中不起作用

以上是关于为啥 __dirname 没有在节点 REPL 中定义?的主要内容,如果未能解决你的问题,请参考以下文章

为啥某些东西可能在节点中执行而不是在 REPL 中?

__dirname 在带有 webpack 捆绑的节点 js 中不起作用

alert(__dirname) 在电子应用程序中没有产生任何输出

Deno 中的 Node.js 的 __dirname 和 __filename 等效项

节点 js heroku 中 pem 文件的密钥

如何使用本机反应像 Node.js 一样获取`__dirname`