【问题标题】:How do I get the path to the current script with Node.js?如何使用 Node.js 获取当前脚本的路径?
【发布时间】:2011-03-09 04:12:27
【问题描述】:

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

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

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

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

【问题讨论】:

标签: node.js


【解决方案1】:

我在再次查看文档后找到了它。我正在寻找的是 __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);
【解决方案2】:

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

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,所以不要在运行时做,但在启动时就可以了,一旦加载,就会被缓存。
  • @Marc 谢谢!一段时间以来,我一直在破解 __dirname 对于每个模块都是本地的这一事实。我的库中有一个嵌套结构,需要在几个地方知道我的应用程序的根目录。很高兴我现在知道该怎么做:D
  • 节点 V8:path.dirname(process.mainModule.filename)
  • @RayFoss 通常对目录分隔符上的字符串操作要小心,解析和连接都可能会出现意外;我认为大多数操作系统都可以容忍过多的斜杠(例如,//////home//////yourname/////// 是一个有效的路径),但是如果您假设路径是否会有结束斜杠,那么在某些情况下,不负责任地使用连接可能会导致一些真正不可读的东西,或者如果斜线意外地附加到 /home/yourname/yourfile.png/ 之类的文件名
【解决方案3】:

使用 __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
【解决方案4】:

此命令返回当前目录:

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 并且它会工作,你不需要构造绝对路径
【解决方案5】:

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 模块?只是我运行的是哪个 Node 版本,还是使用了导入/导出关键字?
  • ES 模块仅适用于 --experimental-modules 标志。
  • --experimental-modules 仅当您运行的节点版本为
  • 谢谢,这为我解决了!在我看来,它对向后兼容性支持非常有用。
  • 是的,这行得通。 @Nickensoul 或在 package.json "type": "module",
【解决方案6】:

主脚本很简单:

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 完美配合 :-)
【解决方案7】:
var settings = 
    JSON.parse(
        require('fs').readFileSync(
            require('path').resolve(
                __dirname, 
                'settings.json'),
            'utf8'));

【讨论】:

  • 请注意,从节点 0.5 开始,您可以只需要一个 JSON 文件。当然,这不会回答这个问题。
【解决方案8】:

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

【讨论】:

  • 这个答案不仅早在几年前就给出了,__dirnameno longer works with ES modules
  • 关于 NodeJs 10,但这个答案是在 2016 年发布的。
【解决方案9】:

我知道这已经很老了,我回答的原始问题被标记为重复并在此处定向,但我遇到了一个问题,试图让 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
 });

【讨论】:

    【解决方案10】:

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

    【讨论】:

    • OP 要求提供所请求的“脚本路径”。 PWD 代表诸如 Process Working Directory 之类的东西,但并非如此。此外,“当前应用”的措辞具有误导性。
    • 这正是我一直在寻找的,即使这个问题的答案是错误的:D
    【解决方案11】:

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

    appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));
    
    • process.pkg 告诉应用程序是否已被pkg 打包。

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

    • require.main.filename 保存了主脚本的完整路径,但 Node 在交互模式下运行时为空。

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

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

    【讨论】:

      【解决方案12】:

      使用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);
      

      【讨论】:

        【解决方案13】:

        包含要导出的模块的任何文件夹中的 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;
        

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

        【讨论】:

          【解决方案14】:

          如果你想在 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;
              }
          }
          

          【讨论】:

          猜你喜欢
          • 2018-04-13
          • 1970-01-01
          • 2012-01-21
          • 2011-01-28
          • 1970-01-01
          • 2018-09-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多