Làm cách nào để có được đường dẫn đến tập lệnh hiện tại với Node.js?


979

Làm cách nào tôi có được đường dẫn đến tập lệnh trong Node.js?

Tôi biết là có process.cwd, nhưng điều đó chỉ đề cập đến thư mục nơi tập lệnh được gọi, không phải của chính tập lệnh. Chẳng hạn, giả sử tôi đang ở /home/kyle/và tôi chạy lệnh sau:

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

Nếu tôi gọi process.cwd(), tôi nhận được /home/kyle/, không /home/kyle/some/dir/. Có cách nào để có được thư mục đó?


6
nodejs.org/docs/latest/api/globals.html liên kết tài liệu của câu trả lời được chấp nhận.
allenhwkim

Câu trả lời:


1393

Tôi tìm thấy nó sau khi xem qua các tài liệu một lần nữa. Những gì tôi đang tìm kiếm là các biến cấp __filename__dirnamemô-đun.

  • __filenamelà tên tập tin của mô-đun hiện tại. Đây là đường dẫn tuyệt đối được giải quyết của tệp mô-đun hiện tại. (ví dụ /home/kyle/some/dir/file.js:)
  • __dirnamelà tên thư mục của mô-đun hiện tại. (ví dụ /home/kyle/some/dir:)

3
Nếu bạn chỉ muốn tên thư mục chứ không phải đường dẫn đầy đủ, bạn có thể làm một cái gì đó như thế này: function getCienDirectoryName () {var fullPath = __dirname; var path = fullPath.split ('/'); var cwd = path [path.length-1]; trả lại cwd; }
Anthony Martin

58
@AnthonyMartin __dirname.split ("/"). Pop ()
19h

6
Đối với những người dùng thử giải pháp @apx (như tôi đã làm :), giải pháp này không hoạt động trên Windows.
Laoujin

36
Hoặc đơn giản hơn__dirname.split(path.sep).pop()
Burgi

47
Hoặcrequire('path').basename(__dirname);
Vyacheslav Cotruta

251

Vì vậy, về cơ bản bạn có thể làm điều này:

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

Sử dụng giải quyết () thay vì nối với '/' hoặc '\' nếu không bạn sẽ gặp phải các vấn đề đa nền tảng.

Lưu ý: __dirname là đường dẫn cục bộ của mô-đun hoặc tập lệnh được bao gồm. Nếu bạn đang viết một plugin cần biết đường dẫn của tập lệnh chính thì đó là:

require.main.filename

hoặc, để chỉ lấy tên thư mục:

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

16
Nếu mục tiêu của bạn chỉ là phân tích cú pháp và tương tác với tệp json, bạn thường có thể thực hiện việc này dễ dàng hơn thông qua var settings = require('./settings.json'). Tất nhiên, đó là fs IO đồng bộ, vì vậy đừng làm điều đó vào thời gian chạy, nhưng tại thời điểm khởi động thì không sao, và một khi nó được tải, nó sẽ được lưu vào bộ nhớ cache.
isaacs

2
@Marc Cảm ơn! Trong một thời gian bây giờ tôi đã hack theo cách của tôi xung quanh thực tế là __dirname là cục bộ cho mỗi mô-đun. Tôi có một cấu trúc lồng nhau trong thư viện của mình và cần biết ở một vài nơi gốc của ứng dụng của tôi. Vui mừng tôi biết làm thế nào bây giờ: D
Thijs Koerselman

Node V8: path.dirname (process.mainModule.filename)
wayofthefuture

Nếu bạn không coi windows là một nền tảng thực sự, chúng ta có thể bỏ qua giải quyết không? BSD, Macos, linux, tizen, symbian, Solaris, android, flutter, webos đều sử dụng / phải không?
Ray Foss


119

Lệnh này trả về thư mục hiện tại:

var currentPath = process.cwd();

Ví dụ: để sử dụng đường dẫn để đọc tệp:

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

Đối với những người không hiểu không đồng bộđồng bộ , xem liên kết này ... stackoverflow.com/a/748235/5287072
DarckBlezzer

16
đây chính xác là những gì OP không muốn ... yêu cầu dành cho đường dẫn của tập lệnh thực thi!
caesarsol

3
Thư mục hiện tại là một điều rất khác nhau. Nếu bạn chạy một cái gì đó như cd /foo; node bar/test.js, thư mục hiện tại sẽ có /foo, nhưng tập lệnh được đặt trong /foo/bar/test.js.
rjmunro

Đó không phải là một câu trả lời hay. Đó là một beacauese logic điều này có thể là con đường ngắn hơn nhiều so với bạn mong đợi.
kris_IV

Tại sao bạn sẽ làm điều này; nếu tệp có liên quan đến thư mục hiện tại bạn có thể đọc text.txtvà nó sẽ hoạt động, bạn không cần xây dựng đường dẫn tuyệt đối
Michael Mrozek

104

Sử dụng __dirname !!

__dirname

Tên thư mục của mô-đun hiện tại. Điều này giống như path.dirname () của __filename.

Ví dụ: chạy nút example.js từ / Users / mjr

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

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

Đối với ESModules bạn muốn sử dụng: import.meta.url


1
Điều này còn tồn tại symlink. Vì vậy, nếu bạn tạo một thùng và cần tìm một tệp, ví dụ path.join (__ dirname, "../example.json"); nó sẽ vẫn hoạt động khi nhị phân của bạn được liên kết trong node_modules / .bin
Jason

2
Câu trả lời này không chỉ được đưa ra nhiều năm trước đó, nó cũng không còn hoạt động với các mô-đun ES .
Dan Dascalescu

48

Khi nói đến kịch bản chính, nó đơn giản như:

process.argv[1]

Từ tài liệu Node.js :

process.argv

Một mảng chứa các đối số dòng lệnh. Phần tử đầu tiên sẽ là 'nút', phần tử thứ hai sẽ là đường dẫn đến tệp JavaScript . Các yếu tố tiếp theo sẽ là bất kỳ đối số dòng lệnh bổ sung.

Nếu bạn cần biết đường dẫn của tệp mô-đun thì hãy sử dụng __filename .


3
Downvoter có thể giải thích tại sao điều này không được khuyến khích?
Tamlyn

1
@Tamlyn Có thể vì process.argv[1]chỉ áp dụng cho tập lệnh chính trong khi __filenametrỏ đến tệp mô-đun đang được thực thi. Tôi cập nhật câu trả lời của tôi để nhấn mạnh sự khác biệt. Tuy nhiên, tôi thấy không có gì sai trong việc sử dụng process.argv[1]. Phụ thuộc vào yêu cầu của một người.
Lukasz Wiktor

10
Nếu tập lệnh chính được khởi chạy với trình quản lý quy trình nút như pm2 process.argv [1] sẽ trỏ đến khả năng thực thi của trình quản lý quy trình /usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js
user3002996

34

Node.js 10 hỗ trợ các mô-đun ECMAScript , ở đâu __dirname__filenamekhông còn khả dụng .

Sau đó, để có được đường dẫn đến mô-đun ES hiện tại, người ta phải sử dụng:

import { fileURLToPath } from 'url';

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

Và đối với thư mục chứa mô-đun hiện tại:

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

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

Làm thế nào để tôi biết nếu tôi đang viết một mô-đun ES hay không? Đây chỉ là vấn đề của phiên bản Node nào tôi đang chạy hay nếu tôi đang sử dụng từ khóa nhập / xuất?
Ed Brannin

2
Các mô-đun ES chỉ có sẵn với --experimental-modulescờ.
Nickensoul

1
--experimental-mô-đun chỉ được yêu cầu nếu bạn đang chạy phiên bản nút là <13.2. chỉ cần đặt tên cho tệp .mjs chứ không phải .js
Brent


24

Mỗi chương trình Node.js có một số biến toàn cục trong môi trường của nó, đại diện cho một số thông tin về quy trình của bạn và một trong số đó là __dirname.


Câu trả lời này không chỉ được đưa ra nhiều năm trước đó, __dirname không còn hoạt động với các mô-đun ES .
Dan Dascalescu

Đó là về NodeJs 10, nhưng câu trả lời này đã được xuất bản vào năm 2016.
Hazarapet Tunanyan

Tôi biết. Câu trả lời có thể được cập nhật khi thay đổi công nghệ.
Dan Dascalescu

13

Tôi biết điều này khá cũ và câu hỏi ban đầu tôi đã trả lời được đánh dấu là trùng lặp và được hướng dẫn ở đây, nhưng tôi gặp phải một vấn đề khi cố gắng làm cho các phóng viên hoa nhài làm việc và không thích ý tưởng rằng tôi phải hạ cấp để nó làm việc Tôi phát hiện ra rằng các phóng viên hoa nhài đã không giải quyết chính xác savePath và thực sự đã đưa đầu ra thư mục báo cáo vào thư mục jasmine-phóng viên thay vì thư mục gốc của nơi tôi chạy gulp. Để làm cho công việc này chính xác, tôi đã kết thúc bằng cách sử dụng process.env.INIT_CWD để lấy Thư mục làm việc hiện tại ban đầu sẽ là thư mục nơi bạn chạy gulp. Hy vọng điều này sẽ giúp được ai đó.

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

8

Bạn có thể sử dụng process.env.PWD để lấy đường dẫn thư mục ứng dụng hiện tại.


2
OP yêu cầu "đường dẫn đến tập lệnh" được yêu cầu. PWD, viết tắt của một cái gì đó như Process Work Directory, không phải vậy. Ngoài ra, cụm từ "ứng dụng hiện tại" là sai lệch.
dmcontador

7

Nếu bạn đang sử dụng pkgđể đóng gói ứng dụng của mình, bạn sẽ thấy biểu thức này hữu ích:

appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));
  • process.pkgcho biết nếu ứng dụng đã được đóng gói bởi pkg.

  • process.execPathgiữ đường dẫn đầy đủ của tệp thực thi, /usr/bin/nodetương tự hoặc đối với các lệnh script trực tiếp ( node test.js) hoặc ứng dụng đóng gói.

  • require.main.filename giữ đường dẫn đầy đủ của tập lệnh chính, nhưng nó trống khi Node chạy ở chế độ tương tác.

  • __dirnamegiữ đường dẫn đầy đủ của tập lệnh hiện tại , vì vậy tôi không sử dụng tập lệnh này (mặc dù đó có thể là những gì OP yêu cầu; sau đó sử dụng tốt hơn appDirectory = process.pkg ? require('path').dirname(process.execPath) : (__dirname || require('path').dirname(process.argv[0]));lưu ý rằng trong chế độ tương tác __dirnamelà trống rỗng.

  • Đối với chế độ tương tác, sử dụng hoặc process.argv[0]để có được đường dẫn đến tệp thực thi Node hoặc process.cwd()để có được thư mục hiện tại.


3

Sử dụng basenamephương pháp của pathmô-đun:

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

Dưới đây là tài liệu ví dụ trên được lấy từ.

Như Dan đã chỉ ra, Node đang làm việc trên các mô-đun ECMAScript với cờ "--experimental-mô-đun". Nút 12 vẫn hỗ trợ __dirname__filename như trên.


Nếu bạn đang sử dụng --experimental-modulescờ, có một cách tiếp cận khác .

Cách khác là lấy đường dẫn đến mô-đun ES hiện tại :

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

Và đối với thư mục chứa mô-đun hiện tại:

import path from 'path';

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

-2

Nếu bạn muốn một cái gì đó giống như $ 0 trong tập lệnh shell, hãy thử điều này:

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;
    }
}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.