ฉันจะหาพา ธ ไปยังสคริปต์ปัจจุบันด้วย Node.js ได้อย่างไร


979

ฉันจะหาเส้นทางไปยังสคริปต์ใน Node.js ได้อย่างไร

ฉันรู้ว่ามีprocess.cwdแต่เพียงอ้างถึงไดเรกทอรีที่สคริปต์ถูกเรียกไม่ใช่สคริปต์เอง ตัวอย่างเช่นสมมติว่าฉันอยู่/home/kyle/และฉันเรียกใช้คำสั่งต่อไปนี้:

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

ถ้าผมเรียกprocess.cwd()ผมรับไม่ได้/home/kyle/ /home/kyle/some/dir/มีวิธีการรับไดเรกทอรีนั้นหรือไม่


6
nodejs.org/docs/latest/api/globals.htmlลิงก์เอกสารของคำตอบที่ยอมรับ
allenhwkim

คำตอบ:


1393

ฉันพบหลังจากดูเอกสารอีกครั้ง สิ่งที่ฉันกำลังมองหาคือ__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; }
Anthony Martin

58
. @AnthonyMartin __dirname.split ( "/") ป๊อป ()
19h

6
สำหรับผู้ที่พยายามแก้ปัญหา @apx (เช่นฉันทำ :) วิธีนี้ไม่สามารถใช้กับ Windows ได้
Laoujin

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

ใช้การแก้ไข () แทนที่จะต่อกับ '/' หรือ '\' มิฉะนั้นคุณจะพบกับปัญหาข้ามแพลตฟอร์ม

หมายเหตุ: __dirname เป็นพา ธ โลคัลของโมดูลหรือสคริปต์ที่รวมไว้ หากคุณกำลังเขียนปลั๊กอินที่จำเป็นต้องรู้เส้นทางของสคริปต์หลักมันคือ:

require.main.filename

หรือเพื่อรับชื่อโฟลเดอร์:

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

16
ถ้าเป้าหมายของคุณเป็นเพียงการแยกและโต้ตอบกับไฟล์ JSON var settings = require('./settings.json')ที่คุณมักจะสามารถทำเช่นนี้ได้ง่ายขึ้นผ่าน แน่นอนว่ามันเป็น fs IO แบบซิงโครนัสดังนั้นอย่าทำในเวลาทำงาน แต่ในเวลาเริ่มต้นมันใช้ได้ดีและเมื่อโหลดแล้วมันจะถูกแคช
isaacs

2
@ Marc ขอบคุณ! ในขณะนี้ฉันกำลังแฮ็คข้อมูลของฉันในความจริงที่ว่า __dirname เป็นชื่อท้องถิ่นของแต่ละโมดูล ฉันมีโครงสร้างซ้อนในห้องสมุดของฉันและจำเป็นต้องรู้ในหลาย ๆ ที่รากของแอปของฉัน ดีใจที่ฉันรู้วิธีการทำเช่นนี้ในขณะนี้: D
Thijs Koerselman

โหนด V8: path.dirname (process.mainModule.filename)
wayofthefuture

หากคุณไม่ถือว่า windows เป็นแพลตฟอร์มจริงเราสามารถข้ามการแก้ไขได้หรือไม่ BSD, Macos, linux, tizen, symbian, Solaris, Android, พลิ้ว, webos ทั้งหมดใช้ / ใช่ไหม?
Ray Foss

นี้ไม่ได้ทำงานร่วมกับโมดูล ES
Dan Dascalescu

119

คำสั่งนี้จะส่งคืนไดเรกทอรีปัจจุบัน:

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

103

ใช้ชื่อ __ !!

__dirname

ชื่อไดเรกทอรีของโมดูลปัจจุบัน นี้เช่นเดียวกับ path.dirname (การ) __filenameของ

ตัวอย่าง: การรันโหนด example.js จาก / Users / mjr

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


1
สิ่งนี้ยังมีชีวิตอยู่เหมือนกัน ดังนั้นหากคุณสร้างถังขยะและต้องการค้นหาไฟล์เช่น path.join (__ dirname, "../example.json"); มันจะยังคงทำงานเมื่อเชื่อมโยงไบนารีของคุณใน node_modules / .bin
เจสัน

2
ไม่เพียง แต่เป็นคำตอบนี้ได้รับปีก่อนก็ยังไม่ได้ทำงานร่วมกับโมดูล ES
Dan Dascalescu

48

เมื่อพูดถึงสคริปต์หลักแล้วมันง่ายเหมือน:

process.argv[1]

จากเอกสาร Node.js :

process.argv

อาร์เรย์ที่มีอาร์กิวเมนต์บรรทัดคำสั่ง องค์ประกอบแรกจะเป็น 'โหน' องค์ประกอบที่สองจะเป็นเส้นทางไปยังแฟ้มจาวาสคริปต์ องค์ประกอบถัดไปจะเป็นอาร์กิวเมนต์บรรทัดคำสั่งเพิ่มเติมใด ๆ

หากคุณจำเป็นต้องรู้เส้นทางของแฟ้มโมดูลแล้วใช้__filename


3
Downvoter ช่วยอธิบายได้ไหมว่าทำไมถึงไม่แนะนำ
Tamlyn

1
@Tamlyn อาจเป็นเพราะprocess.argv[1]ใช้กับสคริปต์หลักเท่านั้นในขณะที่__filenameชี้ไปที่ไฟล์โมดูลที่กำลังดำเนินการ ฉันอัพเดตคำตอบเพื่อเน้นความแตกต่าง process.argv[1]แต่ถึงกระนั้นผมเห็นอะไรที่ไม่ถูกต้องในการใช้ ขึ้นอยู่กับความต้องการ
Lukasz Wiktor

10
ถ้าสคริปต์หลักเปิดตัวกับผู้จัดการกระบวนการโหนดเช่น PM2 process.argv [1] จะชี้ไปที่ปฏิบัติการของ /usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js ผู้จัดการกระบวนการ
user3002996

34

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 หรือไม่? เป็นเรื่องของรุ่นโหนดที่ฉันใช้หรือถ้าฉันใช้คำหลักนำเข้า / ส่งออก
Ed Brannin

2
โมดูล ES ใช้ได้เฉพาะกับการ--experimental-modulesตั้งค่าสถานะ
Nickensoul

1
--experimental-modules จำเป็นเฉพาะเมื่อคุณใช้งานรุ่นโหนดคือ <13.2 เพียงแค่ตั้งชื่อไฟล์. mjs มากกว่า. js
Brent

28
var settings = 
    JSON.parse(
        require('fs').readFileSync(
            require('path').resolve(
                __dirname, 
                'settings.json'),
            'utf8'));

7
เพียงทราบเมื่อโหนด 0.5 คุณสามารถต้องการไฟล์ JSON แน่นอนว่าจะไม่ตอบคำถาม
Kevin Cox

1
__dirname ไม่ได้ทำงานร่วมกับโมดูล ES
Dan Dascalescu

24

ทุกโปรแกรม Node.js __dirnameมีตัวแปรบางอย่างในสภาพแวดล้อมซึ่งหมายถึงข้อมูลบางอย่างเกี่ยวกับกระบวนการของคุณและเป็นหนึ่งของมันก็คือ


ไม่เพียง แต่เป็นคำตอบนี้ได้รับปีก่อนหน้านี้ไม่ได้ทำงานร่วมกับโมดูล__dirname ES
Dan Dascalescu

มันเกี่ยวกับ NodeJs 10 แต่คำตอบนี้ถูกตีพิมพ์ในปี 2559
Hazarapet Tunanyan

ฉันรู้ว่า. คำตอบสามารถอัปเดตเมื่อมีการเปลี่ยนแปลงเทคโนโลยี
Dan Dascalescu

13

ฉันรู้ว่ามันค่อนข้างเก่าและคำถามเดิมที่ฉันตอบกลับถูกทำเครื่องหมายว่าซ้ำกันและกำกับไว้ที่นี่ แต่ฉันพบปัญหาในการพยายามให้จัสมินนักข่าวทำงานและไม่ชอบความคิดที่ฉันต้องลดระดับ สั่งให้มันทำงาน ฉันพบว่าจัสมิน - นักข่าวไม่ได้แก้ไข savePath อย่างถูกต้องและได้วางเอาท์พุทโฟลเดอร์รายงานไว้ในไดเรกทอรีจัสมิน - นักข่าวแทนที่จะเป็นรูทไดเร็กทอรีซึ่งฉันรันอึก เพื่อที่จะทำให้งานนี้ถูกต้องฉันลงเอยด้วยการใช้process.env.INIT_CWDเพื่อรับไดเรกทอรีการทำงานปัจจุบันเริ่มต้นซึ่งควรเป็นไดเรกทอรีที่คุณใช้อึก หวังว่านี่จะช่วยใครซักคน

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 ซึ่งย่อมาจากบางอย่างเช่น Process Working Directory ไม่ใช่เช่นนั้น นอกจากนี้การใช้ถ้อยคำ "แอปปัจจุบัน" ก็ทำให้เข้าใจผิด
dmcontador

7

หากคุณใช้pkgแพ็คเกจของแอปคุณจะพบว่ามีประโยชน์กับนิพจน์นี้:

appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));
  • process.pkgบอกถ้า app pkgได้รับการบรรจุโดย

  • process.execPathเก็บพา ธ แบบเต็มของไฟล์สั่งการซึ่งมี/usr/bin/nodeลักษณะคล้ายกับการเรียกใช้สคริปต์โดยตรง ( node test.js) หรือแอปที่จัดทำแพคเกจ

  • require.main.filename เก็บพา ธ แบบเต็มของสคริปต์หลัก แต่จะว่างเปล่าเมื่อโหนดทำงานในโหมดโต้ตอบ

  • __dirnameเก็บพา ธ แบบเต็มของสคริปต์ปัจจุบันดังนั้นฉันไม่ได้ใช้มัน (แม้ว่ามันอาจเป็นสิ่งที่ OP ขอให้จากนั้นให้ใช้การappDirectory = process.pkg ? require('path').dirname(process.execPath) : (__dirname || require('path').dirname(process.argv[0]));สังเกตว่าในโหมดโต้ตอบ__dirnameนั้นว่างเปล่า

  • สำหรับโหมดการโต้ตอบให้ใช้process.argv[0]เพื่อรับพา ธ ไปยัง Node executable หรือprocess.cwd()เพื่อรับไดเร็กทอรีปัจจุบัน


3

ใช้basenameวิธีการของpathโมดูล:

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

นี่คือเอกสารตัวอย่างข้างต้นนำมาจาก

ดังที่แดนชี้ให้เห็นโหนดกำลังทำงานกับโมดูล ECMAScriptด้วยแฟล็ก "--experimental-modules" โหนด 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

หากคุณต้องการอะไรมากกว่า $ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.