Bagaimana cara mendapatkan path ke skrip saat ini dengan Node.js?

980

Bagaimana saya mendapatkan jalur ke skrip di Node.js?

Saya tahu ada process.cwd, tapi itu hanya merujuk pada direktori tempat skrip dipanggil, bukan skrip itu sendiri. Misalnya, katakan saya di /home/kyle/dan saya menjalankan perintah berikut:

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

Jika saya menelepon process.cwd(), saya mengerti /home/kyle/, tidak /home/kyle/some/dir/. Apakah ada cara untuk mendapatkan direktori itu?

Kyle Slattery
sumber
6
nodejs.org/docs/latest/api/globals.html tautan dokumentasi dari jawaban yang diterima.
allenhwkim

Jawaban:

1394

Saya menemukannya setelah melihat-lihat dokumentasi lagi. Apa yang saya cari adalah __filenamedan __dirnamevariabel modul-tingkat.

  • __filenameadalah nama file dari modul saat ini. Ini adalah jalur absolut terselesaikan dari file modul saat ini. (ex: /home/kyle/some/dir/file.js)
  • __dirnameadalah nama direktori dari modul saat ini. (ex: /home/kyle/some/dir)
Kyle Slattery
sumber
3
Jika Anda hanya menginginkan nama direktori dan bukan path lengkap, Anda dapat melakukan sesuatu seperti ini: function getCurrentDirectoryName () {var fullPath = __dirname; var path = fullPath.split ('/'); var cwd = path [path.length-1]; kembali cwd; }
Anthony Martin
58
@AnthonyMartin __dirname.split ("/"). Pop ()
19h
6
Bagi mereka yang mencoba solusi @apx (seperti yang saya lakukan :), solusi ini tidak berfungsi pada Windows.
Laoujin
36
Atau sederhananya__dirname.split(path.sep).pop()
Burgi
47
Ataurequire('path').basename(__dirname);
Vyacheslav Cotruta
251

Jadi pada dasarnya Anda bisa melakukan ini:

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

Gunakan resolving () alih-alih digabungkan dengan '/' atau '\' yang lain Anda akan mengalami masalah lintas-platform.

Catatan: __dirname adalah lintasan lokal modul atau skrip yang disertakan. Jika Anda menulis sebuah plugin yang perlu mengetahui jalur skrip utama, itu adalah:

require.main.filename

atau, untuk mendapatkan nama folder:

require('path').dirname(require.main.filename)
Marc
sumber
16
Jika tujuan Anda hanya untuk mem-parsing dan berinteraksi dengan file json, Anda seringkali dapat melakukan ini dengan lebih mudah var settings = require('./settings.json'). Tentu saja, ini sinkron untuk IO, jadi jangan lakukan saat run-time, tetapi pada saat startup baik-baik saja, dan begitu dimuat, itu akan di-cache.
isaac
2
@Marc, terima kasih! Untuk sementara sekarang saya meretas fakta bahwa __dirname bersifat lokal untuk setiap modul. Saya memiliki struktur bersarang di perpustakaan saya dan perlu tahu di beberapa tempat akar aplikasi saya. Senang saya tahu bagaimana melakukan ini sekarang: D
Thijs Koerselman
Node V8: path.dirname (process.mainModule.filename)
wayofthefuture
Jika Anda tidak menganggap windows sebagai platform sungguhan, dapatkah kita lewati tekad? BSD, Macos, linux, tizen, symbian, Solaris, android, flutter, webos semua gunakan / benar?
Ray Foss
119

Perintah ini mengembalikan direktori saat ini:

var currentPath = process.cwd();

Misalnya, untuk menggunakan jalur untuk membaca file:

var fs = require('fs');
fs.readFile(process.cwd() + "\\text.txt", function(err, data)
{
    if(err)
        console.log(err)
    else
        console.log(data.toString());
});
Masoud Siahkali
sumber
Bagi mereka yang tidak mengerti Asynchronous dan Sinkron , lihat tautan ini ... stackoverflow.com/a/748235/5287072
DarckBlezzer
16
inilah tepatnya yang tidak diinginkan OP ... permintaannya adalah untuk jalur skrip yang dapat dieksekusi!
caesarsol
3
Direktori saat ini adalah hal yang sangat berbeda. Jika Anda menjalankan sesuatu seperti cd /foo; node bar/test.js, direktori saat ini adalah /foo, tetapi skrip terletak di /foo/bar/test.js.
rjmunro
Itu bukan jawaban yang bagus. Ini berantakan logika beacauese ini bisa menjadi jalan yang jauh lebih pendek dari yang Anda harapkan.
kris_IV
Mengapa Anda melakukan ini; jika file tersebut relatif terhadap direktori saat ini yang baru saja Anda baca text.txtdan itu akan berhasil, Anda tidak perlu membangun path absolut
Michael Mrozek
104

Gunakan __dirname !!

__dirname

Nama direktori modul saat ini. Ini sama dengan path.dirname () dari __filename.

Contoh: menjalankan simpul example.js dari / Users / mjr

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

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

Untuk ESModules Anda ingin menggunakan: import.meta.url

DDD
sumber
1
Ini bertahan symlink juga. Jadi jika Anda membuat bin dan perlu menemukan file, mis. Path.join (__ dirname, "../example.json"); itu masih akan bekerja ketika biner Anda ditautkan di node_modules / .bin
Jason
2
Tidak hanya jawaban ini diberikan bertahun-tahun sebelumnya, itu juga tidak lagi berfungsi dengan modul ES .
Dan Dascalescu
48

Ketika datang ke skrip utama itu sesederhana:

process.argv[1]

Dari dokumentasi Node.js :

process.argv

Array yang berisi argumen baris perintah. Elemen pertama akan menjadi 'simpul', elemen kedua akan menjadi path ke file JavaScript . Elemen berikutnya adalah argumen baris perintah tambahan.

Jika Anda perlu mengetahui jalur file modul, gunakan __filename .

Lukasz Wiktor
sumber
3
Bisakah yang downvoter tolong jelaskan mengapa ini tidak dianjurkan?
Tamlyn
1
@Tamlyn Mungkin karena process.argv[1]hanya berlaku untuk skrip utama sementara __filenamemenunjuk ke file modul yang sedang dieksekusi. Saya memperbarui jawaban saya untuk menekankan perbedaannya. Namun, saya tidak melihat ada yang salah dalam menggunakan process.argv[1]. Tergantung pada kebutuhan seseorang.
Lukasz Wiktor
10
Jika skrip utama diluncurkan dengan manajer proses simpul seperti pm2 process.argv [1] akan mengarah ke executable dari manajer proses /usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js
user3002996
34

Node.js 10 mendukung modul ECMAScript , di mana __dirnamedan __filenametidak lagi tersedia .

Kemudian untuk mendapatkan path ke modul ES saat ini kita harus menggunakan:

import { fileURLToPath } from 'url';

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

Dan untuk direktori yang berisi modul saat ini:

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

const __dirname = dirname(fileURLToPath(import.meta.url));
GOTO 0
sumber
Bagaimana saya tahu kalau saya sedang menulis modul ES atau tidak? Apakah hanya masalah versi Node yang saya jalankan, atau jika saya menggunakan kata kunci impor / ekspor?
Ed Brannin
2
Modul ES hanya tersedia dengan --experimental-modulesflag.
Nickensoul
1
--experimental-modules hanya diperlukan jika Anda menjalankan versi node <13.2. cukup beri nama file .mjs daripada .js
Brent
28
var settings = 
    JSON.parse(
        require('fs').readFileSync(
            require('path').resolve(
                __dirname, 
                'settings.json'),
            'utf8'));
foobar
sumber
7
Hanya sebuah catatan, pada simpul 0,5 Anda hanya dapat memerlukan file JSON. Tentu saja itu tidak akan menjawab pertanyaan itu.
Kevin Cox
1
__dirname tidak lagi berfungsi dengan modul ES .
Dan Dascalescu
24

Setiap program Node.js memiliki beberapa variabel global di lingkungannya, yang mewakili beberapa informasi tentang proses Anda dan salah satunya __dirname.

Hazarapet Tunanyan
sumber
Tidak hanya jawaban ini diberikan bertahun-tahun sebelumnya, __dirname tidak lagi berfungsi dengan modul ES .
Dan Dascalescu
Ini tentang NodeJs 10, tetapi jawaban ini dipublikasikan pada 2016.
Hazarapet Tunanyan
Aku tahu. Jawaban dapat diperbarui saat teknologi berubah.
Dan Dascalescu
13

Saya tahu ini cukup lama, dan pertanyaan awal yang saya jawab ditandai sebagai duplikat dan diarahkan di sini, tetapi saya mengalami masalah ketika mencoba membuat wartawan melati bekerja dan tidak menyukai gagasan bahwa saya harus menurunkan peringkat di Agar itu bekerja. Saya menemukan bahwa reporter melati tidak menyelesaikan savePath dengan benar dan benar-benar meletakkan folder output laporan di direktori reporter melati bukannya direktori root tempat saya berlari menelan. Untuk membuat ini berfungsi dengan benar, saya akhirnya menggunakan process.env.INIT_CWD untuk mendapatkan Direktori Kerja Saat Ini awal yang seharusnya menjadi direktori tempat Anda menjalankan tegukan. Semoga ini bisa membantu seseorang.

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

Anda dapat menggunakan process.env.PWD untuk mendapatkan jalur folder aplikasi saat ini.

AbiSivam
sumber
2
OP meminta "jalur ke skrip" yang diminta. PWD, yang merupakan singkatan dari Process Working Directory, bukan itu. Juga, frasa "aplikasi saat ini" menyesatkan.
dmcontador
7

Jika Anda menggunakan pkguntuk mengemas aplikasi Anda, Anda akan menemukan ungkapan ini berguna:

appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));
  • process.pkgmemberitahu apakah aplikasi telah dikemas oleh pkg.

  • process.execPathmemegang jalur penuh dari file yang dapat dieksekusi, yang /usr/bin/nodeatau serupa untuk pemanggilan langsung skrip ( node test.js), atau aplikasi yang dipaketkan.

  • require.main.filename memegang path lengkap dari skrip utama, tetapi kosong ketika Node berjalan dalam mode interaktif.

  • __dirnamememegang path lengkap dari skrip saat ini , jadi saya tidak menggunakannya (meskipun mungkin apa yang diminta OP; kemudian lebih baik menggunakan appDirectory = process.pkg ? require('path').dirname(process.execPath) : (__dirname || require('path').dirname(process.argv[0]));mencatat bahwa dalam mode interaktif __dirnamekosong.

  • Untuk mode interaktif, gunakan process.argv[0]untuk mendapatkan jalur ke Node yang dapat dieksekusi atau process.cwd()untuk mendapatkan direktori saat ini.

dmcontador
sumber
3

Gunakan basenamemetode pathmodul:

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

Berikut adalah dokumentasi contoh di atas diambil.

Seperti yang ditunjukkan Dan, Node sedang mengerjakan modul - modul ECMAScript dengan flag "--experimental-modules". Node 12 masih mendukung __dirnamedan__filename seperti di atas.


Jika Anda menggunakan --experimental-modulesbendera, ada pendekatan alternatif .

Alternatifnya adalah mendapatkan jalur ke modul ES saat ini :

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

Dan untuk direktori yang berisi modul saat ini:

import path from 'path';

const __dirname = path.dirname(new URL(import.meta.url).pathname);
Michael Cole
sumber
-2

Jika Anda menginginkan sesuatu yang lebih seperti $ 0 dalam skrip shell, coba ini:

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;
    }
}
dmayo3
sumber
__dirnamedan __filenameyang tidak lagi tersedia dengan modul ES .
Dan Dascalescu