运行node bin脚本时确定命令行工作目录

159

我正在创建一个Node.js命令行界面。它被全局安装并使用bin文件来执行。

我计划在我正在工作的文件的根目录打开一个命令窗口,然后只需运行命令即可。但是我无法确定当前的工作目录,因为process.cwd()返回的是node包的目录。最初,我认为由于代码是使用批处理文件作为包装器执行的(这就是bin文件可以在开头不使用node时执行的方式),所以这是不可能的,但是CoffeeScript可以实现。我查看了CoffeeScript源代码,但无法理解(经验不足)。

如果要测试,请创建带有此package.json文件的软件包:

{
  "name": "test-package",
  "version": "1.0.0",
  "bin": {
    "test-package":  "./bin/test-package"
  },
  "main": "/lib/test"
}

这是在bin目录中的测试包文件:

#!/usr/bin/env node

var path = require('path');
var fs   = require('fs');
var lib  = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');

require(lib + '/test');

有人能解释一下吗。

接着尝试获取lib/test目录内的命令行目录。

6个回答

236
  • process.cwd() 返回执行命令的目录(而不是 node 包的目录),除非在应用程序内部通过 'process.chdir' 改变了它。
  • __filename 返回它所在文件的绝对路径。
  • __dirname 返回 __filename 所在目录的绝对路径。

如果需要从您的模块目录加载文件,则需要使用相对路径。

require('../lib/test');

替代

var lib  = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');

require(lib + '/test');

它始终相对于调用它的文件,并且不依赖于当前工作目录。


3
process.chdir()执行后,有没有任何方法可以获取原来的目录? - reergymerej
@reergymerej 在执行 chdir() 前,你可能想要先存储 cwd(例如,var originalCwd = process.cwd();),然后执行你的 process.chdir(),之后可以返回到原始目录。 - Swivel
../lib/test 是可移植的吗? - Sebastian
不,这不是一个便携式的解决方案,因为Windows使用反斜杠。所以如果你尝试在Windows上运行它,它将无法工作。 - zachdyer
2
实际上对于NodeJS来说这都是一样的。即使在Windows上,你也可以方便地按照Unix的方式要求相对路径。因此,../lib/test是可移植的,而Windows的对应项..\lib\test则不是... - Christian Ulbrich
@zachdyer Windows一直使用/和\作为分隔符。有些Windows实用程序不允许/(它们通常将其用作命令前缀),但对于操作系统Windows来说并非如此。 - James Moore

85

当前工作目录

要获取当前工作目录,您可以使用:

process.cwd()

注意,一些脚本(尤其是gulp)会使用process.chdir()来更改当前的工作目录。

Node模块路径

您可以通过以下方式获取当前模块的路径:

  • __filename
  • __dirname

原始目录(启动命令的位置)

如果您从命令行运行脚本,并且希望获取脚本所在的原始目录,无论脚本当前操作的目录是什么,您都可以使用:

process.env.INIT_CWD

与NPM脚本一起工作时的原始目录

有时候希望在当前目录而不是项目根目录中运行NPM脚本。

在npm软件包脚本内部,此变量可用:

$INIT_CWD.

您必须运行最新版本的NPM。如果这个变量不可用,请确保NPM已经更新到最新版。

这将允许您在您的package.json中访问当前路径,例如:

scripts: {
  "customScript": "gulp customScript --path $INIT_CWD"
}

1
process.env.INIT_CWD returns the dir of package.json - vaughan
2
注意,$INIT_CWD 只适用于 Linux。对于 Windows,您必须使用 %INIT_CWD%。我认为可以通过使用 https://www.npmjs.com/package/cross-env 来解决这个问题,但我自己还没有尝试过。 - Stephanie

4

path.resolve('.')也是一个可靠而干净的选择,因为我们几乎总是要require('path')。它将为您提供调用它的目录的绝对路径。


3

另外,如果你只想获取当前 NodeJS 脚本的当前目录,可以尝试这个简单的方法。请注意,在 Node CLI 中将无法使用此方法:

var fs = require('fs'),
    path = require('path');

var dirString = path.dirname(fs.realpathSync(__filename));

// output example: "/Users/jb/workspace/abtest"
console.log('directory to start walking...', dirString);

2

使用ES模块时要注意的警告

根据ECMAScript模块文档

在ES模块中,CommonJS变量__filename__dirname不可用。
相反,可以通过import.meta.url来复制用例。

因此,根据为什么在Node.js中__dirname未定义?,您可以执行以下操作:

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

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

0
这是对我有效的做法:
console.log(process.mainModule.filename);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接