Як отримати шлях до поточного сценарію за допомогою 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
Якщо ви хочете лише ім'я каталогу, а не повний шлях, ви можете зробити щось подібне: функція getCurrentDirectoryName () {var fullPath = __dirname; var path = fullPath.split ('/'); var cwd = шлях [path.length-1]; повернути cwd; }
Ентоні Мартін

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

6
Для тих, хто намагається вирішити @apx (як і я :), це рішення не працює в Windows.
Лауджин

36
Або просто__dirname.split(path.sep).pop()
Бургі

47
Абоrequire('path').basename(__dirname);
В’ячеслав Котрута

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, flutter, webos - все це використовується / правда?
Рей Фосс


118

Ця команда повертає поточний каталог:

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
це саме те, чого ОП не хоче ... запит про шлях виконуваного сценарію!
цезарсол

3
Поточний каталог - це зовсім інша річ. Якщо ви запускаєте щось на зразок cd /foo; node bar/test.js, поточний каталог буде /foo, але сценарій знаходиться в /foo/bar/test.js.
rjmunro

Це не гарна відповідь. Це безлад, оскільки це може бути набагато коротший шлях, ніж ви очікуєте.
kris_IV

Чому б ти коли-небудь робив це; якби файл був відносно поточного каталогу, який ви могли просто прочитати, text.txtі він буде працювати, вам не потрібно будувати абсолютний шлях
Майкл

103

Використовуйте __dirname !!

__dirname

Назва каталогу поточного модуля. Це те саме, що і path.dirname () __filename.

Приклад: запуск node 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
Jason

2
Не тільки ця відповідь була дана роками раніше, вона також більше не працює з модулями ES .
Дан Даскалеску

48

Що стосується основного сценарію, він настільки ж простий, як:

process.argv[1]

З документації Node.js :

процес.argv

Масив, що містить аргументи командного рядка. Перший елемент буде "вузлом", другий елемент - шлях до файлу JavaScript . Наступними елементами будуть будь-які додаткові аргументи командного рядка.

Якщо вам потрібно знати шлях файлу модуля, тоді використовуйте __filename .


3
Чи не могли б пояснити, будь ласка, пояснення, чому це не рекомендується?
Тамлін

1
@Tamlyn Можливо тому, що process.argv[1]стосується лише основного скрипту, а __filenameвказує на файл модуля, який виконується. Я оновлюю свою відповідь, щоб підкреслити різницю. Все-таки я не бачу нічого поганого в використанні process.argv[1]. Залежить від чиїх-небудь вимог.
Лукаш Віктор

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? Це лише питання про те, яку версію вузла я запускаю, чи використовую ключові слова імпорту / експорту?
Ед Браннін

2
Модулі ES доступні лише з --experimental-modulesпрапором.
Нікенсул

1
--experimental-модулі потрібні лише в тому випадку, якщо ви працюєте з версією вузла <13.2. просто назвіть файл .mjs, а не .js
Brent


24

Кожна програма Node.js має у своєму середовищі деякі глобальні змінні, що представляє деяку інформацію про ваш процес та одну з них __dirname.


Не тільки ця відповідь була надана роками раніше, і __dirname більше не працює з модулями ES .
Дан Даскалеску

Йдеться про NodeJs 10, але ця відповідь була опублікована у 2016 році
Hazarapet Tunanyan

Я знаю. Відповіді можуть бути оновлені у міру зміни технологій.
Дан Даскалеску

13

Я знаю, що це досить старе, і оригінальне запитання, на яке я відповідав, позначене як дублікат та спрямоване тут, але я зіткнувся з проблемою, намагаючись змусити жасминів-репортерів працювати, і мені не сподобалася думка, що мені довелося знизити рівень замовити його для роботи. Я з'ясував, що жасмин-репортери неправильно вирішують savePath і фактично ставлять вихід папки звітів у каталог жасминів-репортерів замість кореневого каталогу, де я запускав глоток. Для того, щоб зробити цю роботу правильно, я в кінцевому підсумку використовував 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
 });

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повідомляє, чи додаток було запаковано pkg.

  • process.execPathмістить повний шлях виконуваного файлу, який є /usr/bin/nodeабо подібним для прямого виклику скриптів ( node test.js), або пакетованого додатка.

  • require.main.filename містить повний шлях основного сценарію, але він порожній, коли Node працює в інтерактивному режимі.

  • __dirnameутримує повний шлях поточного сценарію, тому я його не використовую (хоча це може бути те, про що задає ОП; тоді краще використовувати, appDirectory = process.pkg ? require('path').dirname(process.execPath) : (__dirname || require('path').dirname(process.argv[0]));зазначивши, що в інтерактивному режимі __dirnameпорожньо.

  • Для інтерактивного режиму використовуйте або process.argv[0]для отримання шляху до виконуваного вузла, або process.cwd()для отримання поточного каталогу.


3

Використовуйте basenameметод pathмодуля:

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

Ось документація, з якої взято вищеприклад.

Як зазначив Ден, Node працює над модулями ECMAScript із прапором "--experimental-module". Вузол 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;
    }
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.