Dlaczego __dirname nie jest zdefiniowane w węźle REPL?


142

Z podręcznika węzła widzę, że mogę pobrać katalog pliku __dirname, ale z REPL wydaje się, że jest to niezdefiniowane. Czy to nieporozumienie po mojej stronie, czy gdzie jest błąd?

$ node
> console.log(__dirname)
ReferenceError: __dirname is not defined
    at repl:1:14
    at REPLServer.eval (repl.js:80:21)
    at Interface.<anonymous> (repl.js:182:12)
    at Interface.emit (events.js:67:17)
    at Interface._onLine (readline.js:162:10)
    at Interface._line (readline.js:426:8)
    at Interface._ttyWrite (readline.js:603:14)
    at ReadStream.<anonymous> (readline.js:82:12)
    at ReadStream.emit (events.js:88:20)
    at ReadStream._emitKey (tty.js:320:10)


1
Wystąpił ten problem podczas korzystania z eslint, omyłkowo ustawiłem "browser": truezamiast "node": truew moim pliku .eslintrc.json.
— Toivo Säwén

Odpowiedzi:


190

__dirnamejest definiowana tylko w skryptach. Nie jest dostępny w REPL.

spróbuj stworzyć skrypt a.js

console.log(__dirname);

i uruchom go:

node a.js

zobaczysz __dirnamewydrukowane.

Dodano wyjaśnienie w tle: __dirnameoznacza „Katalog tego skryptu”. W REPL nie masz skryptu. Dlatego __dirnamenie miałoby żadnego prawdziwego znaczenia.


6
Nie możesz również używać niektórych zmiennych globalnych wewnątrz modułów RequireJS. Jeśli używasz RequireJS po stronie serwera, zobacz stackoverflow.com/questions/9027429/… .
— Eye

1
Tak, to naprawdę powinno zostać dodane do odpowiedzi Eye, ponieważ to mnie dostało.
— Tomáš Zato - Przywróć Monikę

3
Nie dodawanie tego do skryptu ładowania REPL jest nieprzyjemne. Nie mogę wymyślić żadnego powodu, dla którego by go tam nie było ...
— jcollum

Załadowałem plik skryptu, gdy znajdowałem się w REPL, używając .load script.js. Szkoda, że ​​__dirname nadal nie jest dostępne z poziomu script.js
— Kevin Wheeler

przegłosowano! zaoszczędził mi 15 minut, gdy zastanawiałem się, co dzieje się z wtf
— PirateApp

102

Opierając się na istniejących tutaj odpowiedziach, możesz zdefiniować to w swoim REPL:

__dirname = path.resolve(path.dirname(''));

Lub:

__dirname = path.resolve();

Jeśli żadne pathsegmenty nie zostaną przekazane, path.resolve()zwróci bezwzględną ścieżkę do bieżącego katalogu roboczego.


Lub alternatywy @ Jthorpe:

__dirname = process.cwd();
__dirname = fs.realpathSync('.');
__dirname = process.env.PWD

jeśli używasz, neshmożesz to zdefiniować jako część skryptu ładowania; to
— fajne

1
lub __dirname = process.cwd()lub __dirname=fs.realpathSync('.')lub__dirname = process.env.PWD
— Jthorpe

1
path.dirnamewydaje się nie akceptować już wartości niebędących ciągami w najnowszej wersji głównej 6.0.0, więc pierwsza sugestia w tej odpowiedzi nie zadziała.
— trysis

33

W ES6 użyj:

import path from 'path';
const __dirname = path.resolve();

dostępne również, gdy wywoływany jest węzeł z --experimental-modules


Nie musisz importować podstawowych modułów w REPL; załaduje je dla Ciebie w locie.
— c24w

Daje to bieżący katalog roboczy, a nie katalog bieżącego .jspliku.
— Dirbaio,

@Dirbaio, jaki byłby bieżący .jsplik, gdy jesteś w REPL?
— c24w

@ c24w właśnie sprawdzone, wydaje się, że daje CWD
— Dirbaio

2
To jest źle. __dirnamema być bieżącym katalogiem modułów, ale Twoje rozwiązanie czyni go bieżącym katalogiem roboczym. W jaki sposób ten nonsen otrzymał tyle pozytywnych głosów, jest poza moim zrozumieniem.
— Tomáš Zato - Przywróć Monikę

14

Jeśli używasz modułów node.js , __dirnamea __filenamenie istnieją.

Z dokumentacji Node.js :

Nie wymaga, eksportuje, module.exports, __filename, __dirname

Te zmienne CommonJS nie są dostępne w modułach ES.

requiremożna zaimportować do modułu ES za pomocą module.createRequire().

Odpowiedniki __filenamei __dirnamemogą być tworzone wewnątrz każdego pliku poprzez import.meta.url:

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

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

https://nodejs.org/api/esm.html#esm_no_require_exports_module_exports_filename_dirname


Technicznie jest to jedyna prawidłowa odpowiedź. Wszystkie inne rozwiązania korzystają z bieżącego katalogu roboczego. Co różni się od funkcji __dirname, która jest w rzeczywistości folderem zawierającym aktualnie uruchomiony skrypt.
— Ravi Luthra

8

Jak powiedział @qiao, nie można używać __dirnamew replikacji węzła. Jeśli jednak potrzebujesz tej wartości w konsoli, możesz użyć path.resolve()lub path.dirname(). Chociaż, path.dirname()po prostu da ci „.” więc prawdopodobnie nie jest to pomocne. Koniecznie require('path').


6

Próbowałem też dołączyć do mojej ścieżki używając, path.join(__dirname, 'access.log')ale wyrzucał ten sam błąd.

Oto jak to naprawiłem:

Najpierw zaimportowałem pakiet ścieżki i zadeklarowałem zmienną o nazwie __dirname, a następnie resolve wywołałem metodę ścieżki .

W CommonJS

var path = require("path");

var __dirname = path.resolve();

W ES6 +

import path  from 'path';

const __dirname = path.resolve();

Miłego kodowania .......


3

Wygląda na to, że możesz też to zrobić:

__dirname=fs.realpathSync('.');

oczywiście nie zapomnij fs=require('fs')

(nie jest dokładnie globalny w skryptach węzłów, jest po prostu zdefiniowany na poziomie modułu)


Nie musisz wymagać podstawowych modułów w REPL; załaduje je dla Ciebie w locie.
— c24w

2

Uruchomiłem skrypt z pliku wsadowego jako użytkownik SYSTEM i wszystkie takie zmienne process.cwd(), path.resolve()a wszystkie inne metody dałyby mi ścieżkę do folderu C: \ Windows \ System32 zamiast rzeczywistej ścieżki. Podczas eksperymentów zauważyłem, że kiedy wyrzucany jest błąd, stos zawiera prawdziwą ścieżkę do pliku węzłów.

Oto bardzo hakerski sposób na uzyskanie prawdziwej ścieżki poprzez wywołanie błędu i wyodrębnienie ścieżki z e.stack. Nie używaj.

// this should be the name of currently executed file
const currentFilename = 'index.js';

function veryHackyGetFolder() {
  try {
    throw new Error();
  } catch(e) {
    const fullMsg = e.stack.toString();
    const beginning = fullMsg.indexOf('file:///') + 8;
    const end = fullMsg.indexOf('\/' + currentFilename);
    const dir = fullMsg.substr(beginning, end - beginning).replace(/\//g, '\\');
    return dir;
  }
}

Stosowanie

const dir = veryHackyGetFolder();

Jeśli nie działa to przez REPL, to można użyć __dirnamei __filename.
— c24w

To jedyna odpowiedź, która przynajmniej próbuje dostarczyć poprawne rozwiązanie.
— Tomáš Zato - Przywróć Monikę

@ c24w Próbowałem __dirname, __filename i wszystko inne. W moim przypadku żadne standardowe rozwiązanie nie zadziałało. Oto mój projekt, który uruchamia proces jako SYSTEM z harmonogramu zadań, jeśli się nudzisz github.com/DVLP/Unscheduler. Każde standardowe rozwiązanie, które inaczej działa, jest oczywiście lepsze niż mój hack powyżej :)
— Paweł

1

Chociaż nie jest to rozwiązanie tego problemu, chciałbym je dodać, ponieważ może pomóc innym.

Powinieneś mieć dwa podkreślenia przed dirname, a nie jeden podkreślenie ( __dirnamenie _dirname).

NodeJS Docs


__dirname (z dwoma podkreśleniami) nie działa w REPL
— Aaron J Spetner

1

Jeśli masz node __dirname not definedze node --experimental-modulesmożna zrobić:

const __dirname = path.dirname(import.meta.url)
                      .replace(/^file:\/\/\//, '') // can be usefull

Ponieważ inny przykład działa tylko z katalogiem bieżącym / pwd, a nie innym katalogiem.


0

czasami tworzymy plik z rozszerzeniem .js i dodajemy consol.log (_dirname); ale napotykamy błędy, spieszymy się, więc zapominamy o dodaniu jeszcze jednego podkreślenia przed "dirname", więc mamy do czynienia z błędem odniesienia. Prawidłowa składnia to consol.log (__ dirname);

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.