Как мне получить путь к текущему скрипту с Node.js?


980

Как бы я получить путь к сценарию в 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

Ответы:


1395

Я нашел это после просмотра документации снова. То, что я искал, это переменные уровня __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; }
Энтони Мартин

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

Используйте resol () вместо объединения с '/' или '\', иначе вы столкнетесь с кроссплатформенными проблемами.

Примечание: __dirname - это локальный путь модуля или включенного скрипта. Если вы пишете плагин, который должен знать путь основного скрипта, это:

require.main.filename

или просто получить имя папки:

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

16
Если ваша цель - просто проанализировать файл json и взаимодействовать с ним, вы часто можете сделать это проще с помощью var settings = require('./settings.json'). Конечно, это синхронный fs IO, поэтому не делайте этого во время выполнения, но во время запуска все в порядке, и после загрузки он будет кэширован.
Исааки

2
@ Марк Спасибо! Некоторое время я пытался понять, что __dirname является локальным для каждого модуля. У меня есть вложенная структура в моей библиотеке, и мне нужно знать в нескольких местах корень моего приложения. Рад, что я знаю, как это сделать сейчас: D
Тийс Коерсельман

Узел V8: путь.dirname (process.mainModule.filename)
путь в будущем

Если вы не считаете Windows реальной платформой, можем ли мы пропустить решение? BSD, Macos, Linux, Tizen, Symbian, Solaris, Android, Flutter, Webos все используют / правильно?
Рэй Фосс


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 не хочет ... запрос на путь исполняемого скрипта!
Цезарсоль

3
Текущий каталог - это совсем другое. Если вы запустите что-то вроде cd /foo; node bar/test.js, текущий каталог будет /foo, но сценарий находится в /foo/bar/test.js.
rjmunro

Это не очень хороший ответ. Это запутанная логика, потому что это может быть гораздо более короткий путь, чем вы ожидаете.
kris_IV

Зачем тебе это делать? если файл был относительно текущего каталога, который вы могли бы просто прочитать, text.txtи он работал бы, вам не нужно составлять абсолютный путь
Майкл

105

Используйте __dirname !!

__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
Jason

2
Этот ответ был дан не только несколькими годами ранее, но и с модулями ES .
Дан Даскалеску

48

Когда дело доходит до основного скрипта, это так просто:

process.argv[1]

Из документации Node.js :

process.argv

Массив, содержащий аргументы командной строки. Первым элементом будет «узел», вторым элементом будет путь к файлу JavaScript . Следующими элементами будут любые дополнительные аргументы командной строки.

Если вам нужно знать путь к файлу модуля, используйте __filename .


3
Может ли downvoter объяснить, почему это не рекомендуется?
Тамлин

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 или нет? Это просто вопрос, какую версию Node я использую, или я использую ключевые слова импорта / экспорта?
Эд Браннин

2
Модули ES доступны только с --experimental-modulesфлагом.
Nickensoul

1
--experimental-modules требуется только в том случае, если вы используете версию узла <13.2. просто назовите файл .mjs, а не .js
Brent


24

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


Этот ответ был дан не только несколькими годами ранее, __dirname но и с модулями ES .
Дан Даскалеску

Речь идет о NodeJs 10, но этот ответ был опубликован в 2016 году.
Хазарапет Тунанян

Я знаю. Ответы могут быть обновлены по мере изменения технологии.
Дан Даскалеску

13

Я знаю, что это довольно старый вопрос, и исходный вопрос, на который я отвечал, помечен как дубликат и направлен сюда, но я столкнулся с проблемой, пытавшейся заставить журналистов-жасминов работать, и мне не понравилась идея, что мне пришлось понизить рейтинг для того чтобы он работал. Я обнаружил, что jasmine-reporters неправильно разрешал savePath и фактически помещал выходные данные папки отчетов в каталог jasmine-reporters вместо корневого каталога, в котором я запускал gulp. Для правильной работы я в конечном итоге использовал 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
ОП запрашивает запрошенный «путь к скрипту». 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аналогичен прямому вызову scripts ( node test.js) или упакованного приложения.

  • require.main.filename содержит полный путь основного скрипта, но он пуст, когда Node работает в интерактивном режиме.

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

  • В интерактивном режиме используйте либо process.argv[0]для получения пути к исполняемому файлу Node, либо process.cwd()для получения текущего каталога.


3

Используйте basenameметод pathмодуля:

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

Вот документация, из которой взят пример выше.

Как отметил Дэн, Node работает над модулями 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;
    }
}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.