Jak uzyskać ścieżkę do bieżącego skryptu za pomocą Node.js?


979

Jak uzyskać ścieżkę do skryptu w Node.js?

Wiem, że istnieje process.cwd, ale dotyczy to tylko katalogu, w którym skrypt został wywołany, a nie samego skryptu. Na przykład powiedz, że jestem /home/kyle/i uruchamiam następujące polecenie:

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

Jeśli zadzwonię process.cwd(), mam /home/kyle/, nie /home/kyle/some/dir/. Czy istnieje sposób na uzyskanie tego katalogu?


6
nodejs.org/docs/latest/api/globals.html link do dokumentacji zaakceptowanej odpowiedzi.
allenhwkim

Odpowiedzi:


1392

Znalazłem to po ponownym przejrzeniu dokumentacji. Co szukałem były __filenamei __dirnamezmienne moduł poziomie.

  • __filenameto nazwa pliku bieżącego modułu. Jest to rozwiązana ścieżka bezwzględna bieżącego pliku modułu. (np /home/kyle/some/dir/file.js)
  • __dirnameto nazwa katalogu bieżącego modułu. (np /home/kyle/some/dir)

3
Jeśli chcesz tylko nazwę katalogu, a nie pełną ścieżkę, możesz zrobić coś takiego: function getCurrentDirectoryName () {var fullPath = __dirname; var path = fullPath.split ('/'); var cwd = ścieżka [ścieżka.length-1]; zwróć cwd; }
Anthony Martin

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

6
Dla tych, którzy próbują rozwiązania @apx (tak jak ja :), to rozwiązanie nie działa w systemie Windows.
Laoujin

36
Lub po prostu__dirname.split(path.sep).pop()
Burgi

47
Lubrequire('path').basename(__dirname);
Wiaczesław Cotruta

251

Zasadniczo możesz to zrobić:

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

Skorzystaj z metody resolver () zamiast łączenia z „/” lub „\”, w przeciwnym razie wystąpią problemy z wieloma platformami.

Uwaga: __dirname to lokalna ścieżka modułu lub dołączonego skryptu. Jeśli piszesz wtyczkę, która musi znać ścieżkę głównego skryptu, jest to:

require.main.filename

lub, aby po prostu uzyskać nazwę folderu:

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

16
Jeśli Twoim celem jest po prostu parsowanie i interakcja z plikiem json, często możesz to zrobić łatwiej var settings = require('./settings.json'). Oczywiście jest to synchroniczne we / wy fs, więc nie rób tego w czasie wykonywania, ale podczas uruchamiania jest w porządku, a po załadowaniu zostanie buforowane.
isaacs

2
@Marc Dzięki! Od jakiegoś czasu rąbałam się wokół faktu, że __dirname jest lokalny dla każdego modułu. Mam zagnieżdżoną strukturę w swojej bibliotece i muszę znać w kilku miejscach katalog główny mojej aplikacji. Cieszę się, że wiem, jak to zrobić teraz: D
Thijs Koerselman

Węzeł V8: ścieżka.dirname (process.mainModule.filename)
wayofthefuture

Jeśli nie uważasz Windowsa za prawdziwą platformę, czy możemy pominąć rozwiązanie? BSD, Macos, Linux, Tizen, Symbian, Solaris, Android, Trzepotanie, Webos wszyscy używają / prawda?
Ray Foss


118

To polecenie zwraca bieżący katalog:

var currentPath = process.cwd();

Na przykład, aby użyć ścieżki do odczytania pliku:

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

Dla tych, którzy nie rozumieli Asynchronous i synchronicznego , zobacz ten link ... stackoverflow.com/a/748235/5287072
DarckBlezzer

16
to jest dokładnie to, czego OP nie chce ... żądanie dotyczy ścieżki skryptu wykonywalnego!
caesarsol

3
Aktualny katalog to coś zupełnie innego. Jeśli uruchomisz coś takiego cd /foo; node bar/test.js, bieżący katalog będzie /foo, ale skrypt znajduje się w /foo/bar/test.js.
rjmunro

To nie jest dobra odpowiedź. To bałagan logika, ponieważ może to być znacznie krótsza ścieżka niż się spodziewasz.
kris_IV

Dlaczego miałbyś to robić; jeśli plik text.txtbyłby względny do bieżącego katalogu, który można po prostu odczytać i działałby, nie trzeba budować ścieżki bezwzględnej
Michael Mrozek

102

Użyj __dirname !!

__dirname

Nazwa katalogu bieżącego modułu. To samo co path.dirname () z __filename.

Przykład: uruchamianie węzła example.js z katalogu / Users / mjr

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

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

W przypadku modułów ESM, których chcesz użyć: import.meta.url


1
To także przetrwa dowiązania symboliczne. Więc jeśli utworzysz bin i chcesz znaleźć plik, np. Path.join (__ nazwa_katalogu, „../example.json”); nadal będzie działać, gdy twój plik binarny jest połączony w node_modules / .bin
Jason

2
Ta odpowiedź nie tylko została podana wiele lat wcześniej, ale także nie działa z modułami ES .
Dan Dascalescu

48

Jeśli chodzi o główny skrypt, jest tak prosty, jak:

process.argv[1]

Z dokumentacji Node.js :

process.argv

Tablica zawierająca argumenty wiersza poleceń. Pierwszym elementem będzie „węzeł”, drugim elementem będzie ścieżka do pliku JavaScript . Kolejnymi elementami będą wszelkie dodatkowe argumenty wiersza poleceń.

Jeśli chcesz poznać ścieżkę pliku modułu, użyj __nazwa_pliku .


3
Czy downvoter mógłby wyjaśnić, dlaczego nie jest to zalecane?
Tamlyn,

1
@Tamlyn Może dlatego, że process.argv[1]dotyczy tylko głównego skryptu, podczas gdy __filenamewskazuje plik wykonywanego modułu. Aktualizuję swoją odpowiedź, aby podkreślić różnicę. Mimo to nie widzę nic złego w użyciu process.argv[1]. Zależy od własnych wymagań.
Łukasz Wiktor

10
Jeśli główny skrypt został uruchomiony z menedżerem procesów węzłowych, takim jak pm2 process.argv [1], wskaże plik wykonywalny menedżera procesów /usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js
użytkownik3002996

34

Node.js 10 obsługuje moduły ECMAScript , gdzie __dirnamei __filenamenie są już dostępne .

Następnie, aby uzyskać ścieżkę do bieżącego modułu ES, należy użyć:

import { fileURLToPath } from 'url';

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

A dla katalogu zawierającego bieżący moduł:

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

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

Skąd mam wiedzieć, czy piszę moduł ES, czy nie? Czy to tylko kwestia, którą wersję Węzła używam, czy też używam słów kluczowych importu / eksportu?
Ed Brannin,

2
Moduły ES dostępne tylko z --experimental-modulesflagą.
Nickensoul

1
--experymentalne-moduły są wymagane tylko, jeśli korzystasz z wersji węzła <13.2. po prostu nazwij plik .mjs zamiast .js
Brent



13

Wiem, że jest to dość stare, a pierwotne pytanie, na które odpowiadałem, jest oznaczone jako zduplikowane i skierowane tutaj, ale natknąłem się na problem próbujący zmusić reporterów jasmine do pracy i nie podobał mi się pomysł, że musiałem obniżyć wersję aby działało. Dowiedziałem się, że jasmine-reporters nie rozwiązuje poprawnie savePath i tak naprawdę umieszczam dane wyjściowe folderu raportów w katalogu jasmine-reporters zamiast w katalogu głównym, w którym uruchomiłem gulp. W celu dokonania tej pracy właściwie skończyło się używając process.env.INIT_CWD uzyskać wstępną bieżącego katalogu roboczego, który powinien być katalogiem, w którym prowadził łyk. Mam nadzieję, że to komuś pomoże.

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

8

Możesz użyć process.env.PWD, aby uzyskać bieżącą ścieżkę do folderu aplikacji.


2
OP prosi o podanie „ścieżki do skryptu”. PWD, co oznacza coś takiego jak Process Working Directory, to nie to. Również sformułowanie „bieżąca aplikacja” wprowadza w błąd.
dmcontador,

7

Jeśli używasz pkgdo pakowania aplikacji, przydatne będzie to wyrażenie:

appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));
  • process.pkginformuje, czy aplikacja została spakowana przez pkg.

  • process.execPathprzechowuje pełną ścieżkę do pliku wykonywalnego, który jest /usr/bin/nodepodobny w przypadku bezpośrednich wywołań skryptów ( node test.js) lub spakowanej aplikacji.

  • require.main.filename zawiera pełną ścieżkę głównego skryptu, ale jest pusty, gdy Node działa w trybie interaktywnym.

  • __dirnamezawiera pełną ścieżkę bieżącego skryptu, więc nie używam go (chociaż może być to, o co prosi OP; lepiej użyj, appDirectory = process.pkg ? require('path').dirname(process.execPath) : (__dirname || require('path').dirname(process.argv[0]));zauważając, że w trybie interaktywnym __dirnamejest pusty.

  • W trybie interaktywnym użyj albo, process.argv[0]aby uzyskać ścieżkę do pliku wykonywalnego węzła lub process.cwd()aby uzyskać bieżący katalog.


3

Skorzystaj z basenamemetody pathmodułu:

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

Oto dokumentacja, z której wzięto powyższy przykład.

Jak zauważył Dan, Node pracuje nad modułami ECMAScript z flagą „--experimental-modules”. Węzeł 12 nadal obsługuje __dirnamei__filename jak wyżej.


Jeśli używasz --experimental-modulesflagi, istnieje alternatywne podejście .

Alternatywą jest uzyskanie ścieżki do bieżącego modułu ES :

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

A dla katalogu zawierającego bieżący moduł:

import path from 'path';

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

-2

Jeśli chcesz czegoś więcej jak 0 $ w skrypcie powłoki, spróbuj tego:

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

__dirnamei nie__filenamejuż dostępne z modułami ES .
Dan Dascalescu
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.