ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 Node.js 获取当前脚本的路径?

如何在 Node.js 中获取脚本的路径?

我知道有 process.cwd,但这只是指调用脚本的目录,而不是脚本本身。例如,假设我在 /home/kyle/ 中并运行以下命令:

node /home/kyle/some/dir/file.js

如果我调用 process.cwd(),我会得到 /home/kyle/,而不是 /home/kyle/some/dir/。有没有办法得到那个目录?

nodejs.org/docs/latest/api/globals.html 已接受答案的文档链接。

d
doom

再次查看文档后,我找到了它。我正在寻找的是 __filename__dirname 模块级变量。

__filename 是当前模块的文件名。这是当前模块文件的解析绝对路径。 (例如:/home/kyle/some/dir/file.js)

__dirname 是当前模块的目录名。 (例如:/home/kyle/some/dir)


如果你只想要目录名而不是完整路径,你可以这样做: function getCurrentDirectoryName() { var fullPath = __dirname; var path = fullPath.split('/'); var cwd = 路径[path.length-1];返回 cwd; }
@AnthonyMartin __dirname.split("/").pop()
对于那些尝试@apx 解决方案的人(就像我所做的那样:),这个解决方案在 Windows 上不起作用。
或者干脆__dirname.split(path.sep).pop()
require('path').basename(__dirname);
M
Marc

所以基本上你可以这样做:

fs.readFile(path.resolve(__dirname, 'settings.json'), 'UTF-8', callback);

使用 resolve() 而不是连接 '/' 或 '\' 否则你会遇到跨平台问题。

注意:__dirname 是模块或包含脚本的本地路径。如果您正在编写一个需要知道主脚本路径的插件,它是:

require.main.filename

或者,仅获取文件夹名称:

require('path').dirname(require.main.filename)

如果您的目标只是解析 json 文件并与之交互,您通常可以通过 var settings = require('./settings.json') 更轻松地做到这一点。当然是同步fs IO,所以不要在运行时做,但在启动时就可以了,一旦加载,就会被缓存。
@马克谢谢!一段时间以来,我一直在破解 __dirname 对于每个模块都是本地的这一事实。我的库中有一个嵌套结构,需要在几个地方知道我的应用程序的根目录。很高兴我现在知道该怎么做:D
节点 V8:path.dirname(process.mainModule.filename)
@RayFoss 通常对目录分隔符上的字符串操作要小心,解析和连接都可能会出现意外;我认为大多数操作系统都可以容忍过多的斜杠(例如,//////home//////yourname/////// 是一个有效的路径),但是如果您假设路径是否会有结束斜杠,那么在某些情况下,不负责任地使用连接可能会导致某些内容不可读,或者如果斜杠意外地附加到 /home/yourname/yourfile.png/ 之类的文件名
P
Playdome.io

使用 __dirname!!

__dirname

当前模块的目录名。这与 __filename 的 path.dirname() 相同。

示例:从 /Users/mjr 运行节点 example.js

console.log(__dirname);
// Prints: /Users/mjr
console.log(path.dirname(__filename));
// Prints: /Users/mjr

https://nodejs.org/api/modules.html#modules_dirname

对于您想要使用的 ESModules:import.meta.url


这也可以在符号链接中幸存下来。因此,如果您创建一个 bin 并需要查找一个文件,例如 path.join(__dirname, "../example.json");当您的二进制文件链接到 node_modules/.bin 时,它仍然可以工作
这个答案不仅早在几年前就给出了,而且no longer works with ES modules
d
dYale

此命令返回当前目录:

var currentPath = process.cwd();

例如,要使用路径读取文件:

var fs = require('fs');
fs.readFile(process.cwd() + "\\text.txt", function(err, data)
{
    if(err)
        console.log(err)
    else
        console.log(data.toString());
});

对于不了解 异步同步 的人,请参阅此链接... stackoverflow.com/a/748235/5287072
这正是 OP 不想要的……请求是针对可执行脚本的路径!
当前目录是一个非常不同的东西。如果您运行 cd /foo; node bar/test.js 之类的东西,当前目录将是 /foo,但脚本位于 /foo/bar/test.js
这不是一个好的答案。这是一团糟的逻辑,因为这可能比您预期的要短得多。
你为什么要这样做;如果文件是相对于当前目录的,您只需读取 text.txt 并且它会工作,您不需要构造绝对路径
G
GOTO 0

Node.js 10 支持 ECMAScript modules,其中 __dirname and __filename are no longer available

然后要获得 path to the current ES module 必须使用:

import { fileURLToPath } from 'url';

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

对于包含当前模块的目录:

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

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

我怎么知道我是否正在编写 ES 模块?只是我运行的是哪个节点版本,还是我使用了导入/导出关键字?
ES 模块仅适用于 --experimental-modules 标志。
--experimental-modules 仅当您运行的节点版本 < 13.2 时才需要。只需将文件命名为 .mjs 而不是 .js
谢谢,这为我解决了!在我看来,它对于向后兼容性支持非常有用。
是的,这行得通。 @Nickensoul 或在 package.json "type": "module",
C
Community

当涉及到主脚本时,它很简单:

process.argv[1]

Node.js documentation

process.argv 包含命令行参数的数组。第一个元素是“节点”,第二个元素是 JavaScript 文件的路径。下一个元素将是任何附加的命令行参数。

如果您需要知道模块文件的路径,请使用 __filename


否决投票者可以解释为什么不推荐这样做吗?
@Tamlyn 也许是因为 process.argv[1] 仅适用于主脚本,而 __filename 指向正在执行的模块文件。我更新了我的答案以强调差异。不过,我认为使用 process.argv[1] 没有任何问题。取决于一个人的要求。
如果使用 pm2 之类的节点进程管理器启动主脚本,则 process.argv[1] 将指向进程管理器 /usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js 的可执行文件
@LukaszWiktor 非常感谢!与自定义 Node.js CLI 完美配合 :-)
C
Community
var settings = 
    JSON.parse(
        require('fs').readFileSync(
            require('path').resolve(
                __dirname, 
                'settings.json'),
            'utf8'));

请注意,从节点 0.5 开始,您可以只需要一个 JSON 文件。当然,这不会回答这个问题。
O
Omar Ali

每个 Node.js 程序在其环境中都有一些全局变量,它们代表有关您的进程的一些信息,其中之一是 __dirname


这个答案不仅是几年前给出的,__dirname no longer works with ES modules
这是关于 NodeJs 10,但这个答案是在 2016 年发布的。
M
Mike

我知道这已经很老了,我回答的原始问题被标记为重复并指向此处,但我遇到了一个试图让 jasmine-reporters 工作的问题,并且不喜欢我不得不降级的想法命令它工作。我发现 jasmine-reporters 没有正确解析 savePath,实际上是将报告文件夹输出放在 jasmine-reporters 目录中,而不是我运行 gulp 的根目录中。为了使这项工作正常进行,我最终使用 process.env.INIT_CWD 来获取初始的当前工作目录,它应该是您运行 gulp 的目录。希望这可以帮助某人。

var reporters = require('jasmine-reporters');
var junitReporter = new reporters.JUnitXmlReporter({
  savePath: process.env.INIT_CWD + '/report/e2e/',
  consolidateAll: true,
  captureStdout: true
 });

A
AbiSivam

您可以使用 process.env.PWD 来获取当前的应用程序文件夹路径。


OP 要求提供所请求的“脚本路径”。 PWD 代表诸如 Process Working Directory 之类的东西,但并非如此。此外,“当前应用程序”的措辞具有误导性。
d
dmcontador

如果您使用 pkg 打包您的应用程序,您会发现这个表达式很有用:

appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));

process.pkg 告诉应用程序是否已被 pkg 打包。

process.execPath 保存可执行文件的完整路径,即 /usr/bin/node 或类似的直接调用脚本(节点 test.js)或打包应用程序的路径。

require.main.filename 包含主脚本的完整路径,但当 Node 以交互模式运行时,它是空的。

__dirname 保存当前脚本的完整路径,所以我没有使用它(尽管它可能是 OP 要求的;那么最好使用 appDirectory = process.pkg ? require('path').dirname(process.execPath) : ( __dirname || require('path').dirname(process.argv[0])); 注意在交互模式下 __dirname 是空的。

对于交互模式,使用 process.argv[0] 获取 Node 可执行文件的路径,或者使用 process.cwd() 获取当前目录。


M
Michael Cole

使用 path 模块的 basename 方法:

var path = require('path');
var filename = path.basename(__filename);
console.log(filename);

Here 是上述示例的文档。

正如 Dan 指出的那样,Node 正在使用“--experimental-modules”标志处理 ECMAScript modules。节点 12 仍为 supports __dirname and __filename,如上。

如果您使用 --experimental-modules 标志,则有一个 alternative approach

另一种方法是获取 path to the current ES module

const __filename = new URL(import.meta.url).pathname;

对于包含当前模块的目录:

import path from 'path';

const __dirname = path.dirname(new URL(import.meta.url).pathname);

在 Windows 上,使用此方法返回的路径中有一个前导 /。
I
Idan_Krupnik

NodeJS 公开了一个名为 __dirname 的全局变量。

__dirname 返回 JavaScript 文件所在文件夹的完整路径。

因此,例如,对于 Windows,如果我们使用以下行创建一个脚本文件:

console.log(__dirname);

并使用以下命令运行该脚本:

node ./innerFolder1/innerFolder2/innerFolder3/index.js

输出将是:C:\Users...\innerFolder1\innerFolder2\innerFolder3


__dirname 未在 ES 模块范围内定义
A
Andy Lorenz

包含要导出的模块的任何文件夹中的 index.js

const entries = {};
for (const aFile of require('fs').readdirSync(__dirname, { withFileTypes: true }).filter(ent => ent.isFile() && ent.name !== 'index.js')) {
  const [ name, suffix ] = aFile.name.split('.');
  entries[name] = require(`./${aFile.name}`);
}

module.exports = entries;

这将在当前目录的根目录中找到所有文件,要求并导出与文件名词干具有相同导出名称的每个文件。


d
dmayo3

如果你想在 shell 脚本中得到更像 $0 的东西,试试这个:

var path = require('path');

var command = getCurrentScriptPath();

console.log(`Usage: ${command} <foo> <bar>`);

function getCurrentScriptPath () {
    // Relative path from current working directory to the location of this script
    var pathToScript = path.relative(process.cwd(), __filename);

    // Check if current working dir is the same as the script
    if (process.cwd() === __dirname) {
        // E.g. "./foobar.js"
        return '.' + path.sep + pathToScript;
    } else {
        // E.g. "foo/bar/baz.js"
        return pathToScript;
    }
}

__dirname__filenameno longer available with ES modules