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


979

我如何获得Node.js中脚本的路径?

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

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

如果我打电话process.cwd(),我/home/kyle/不会/home/kyle/some/dir/。有没有办法获取该目录?


Answers:


1392

我在再次浏览文档后才找到它。我要寻找的是__filename__dirname模块级别的变量。

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

3
如果只需要目录名而不是完整路径,则可以执行以下操作:function getCurrentDirectoryName(){var fullPath = __dirname; var path = fullPath.split('/'); var cwd = path [path.length-1]; 返回cwd; }
安东尼·马丁

58
。@AnthonyMartin __dirname.split( “/”)POP()
19H

6
对于那些尝试@apx解决方案的人(像我一样:),该解决方案在Windows上不起作用。
老金2015年

36
或者干脆__dirname.split(path.sep).pop()
BURGI

47
require('path').basename(__dirname);
Vyacheslav Cotruta

251

因此,基本上,您可以这样做:

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

使用resolve()而不是与“ /”或“ \”串联,否则会遇到跨平台问题。

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

require.main.filename

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

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

16
如果您的目标只是解析json文件并与之交互,则通常可以通过轻松实现var settings = require('./settings.json')。当然,它是同步fs IO,因此不要在运行时执行它,但是在启动时就可以了,一旦加载,就将被缓存。
isaacs,2012年

2
@马克谢谢!一段时间以来,我一直在绕着__dirname是每个模块本地的事实来破解自己的方式。我的库中有一个嵌套结构,需要在几个地方知道我的应用程序的根目录。很高兴我现在知道如何进行操作:D
Thijs Koerselman

节点V8:path.dirname(process.mainModule.filename)
未来之路

如果您不认为Windows是真正的平台,我们可以跳过解析吗?BSD,Macos,Linux,Tizen,Symbian,Solaris,Android,Flutter,WebOS都使用/对吗?
雷·福斯


118

此命令返回当前目录:

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
DarckBlezzer

16
这正是OP所不想要的...请求是针对可执行脚本的路径的!
caesarsol

3
当前目录是完全不同的事情。如果运行类似的命令cd /foo; node bar/test.js,则当前目录为/foo,但脚本位于/foo/bar/test.js
rjmunro

这不是一个好答案。逻辑上是混乱的,这比您预期的要短得多。
kris_IV

你为什么要这样做?如果文件相对于您当前可以读取的当前目​​录text.txt并且可以工作,则无需构造绝对路径
Michael Mrozek '19

102

使用__dirname!

__dirname

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

示例:从/ 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

对于ESModule,您将要使用: import.meta.url


1
这也幸免于符号链接。因此,如果您创建一个bin并需要找到一个文件,例如path.join(__ dirname,“ ../example.json”); 当您的二进制文件链接到node_modules / .bin中时,它仍然可以工作
Jason

2
这个答案不仅早在几年前就给出了,它也不再适用于ES模块
Dan Dascalescu

48

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

process.argv[1]

Node.js文档中

process.argv

包含命令行参数的数组。第一个元素是'node',第二个元素是JavaScript文件的路径。接下来的元素将是任何其他命令行参数。

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


3
请下降投票者解释一下为什么不建议这样做吗?
塔林

1
@Tamlyn可能是因为process.argv[1]仅适用于主脚本,而__filename指向正在执行的模块文件。我更新我的答案以强调差异。不过,我发现使用没错process.argv[1]。取决于一个人的要求。
卢卡斯·威克多

10
如果主脚本是使用节点进程管理器(如pm2 process.argv [1])启动的,则将指向进程管理器的可执行文件/usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js
user3002996

33

Node.js的10个支持ECMAScript的模块,其中__dirname__filename不再可用

然后,要使用当前ES模块路径,必须使用:

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模块?仅仅是我运行的是哪个版本的节点,还是我使用的是import / export关键字?
Ed Brannin

2
ES模块仅带有--experimental-modules标志。
Nickensoul

1
--experimental-modules仅在您运行的节点版本小于13.2时才需要。只是将文件命名为.mjs而不是.js
Brent



13

我知道这已经很老了,我最初回答的问题被标记为重复并直接指向此处,但是我遇到了一个问题,试图让茉莉花记者正常工作,并且不喜欢我必须降级的想法。使其工作。我发现jasmine-reporters不能正确解析savePath,实际上是将reports文件夹输出放在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
 });

8

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


2
OP要求提供所请求的“脚本路径”。PWD代表“进程工作目录”之类的东西,并非如此。同样,“当前应用”的措词具有误导性。
dmcontador

7

如果您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对于直接调用脚本(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()获取当前目录。


3

使用模块的basename方法path

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

是上面示例的文档。

正如Dan所指出的那样,Node正在使用“ --experimental-modules”标志来处理ECMAScript模块。节点12仍支持__dirname__filename


如果您使用--experimental-modules标志,则有另一种方法

另一种方法是获取当前ES模块路径

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

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

import path from 'path';

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

-2

如果要在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并且__filename不再与ES模块
Dan Dascalescu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.