Como obtenho o caminho para o script atual com o Node.js?

979

Como obteria o caminho para o script no Node.js?

Eu sei que há process.cwd, mas isso se refere apenas ao diretório em que o script foi chamado, não ao próprio script. Por exemplo, diga que eu estou /home/kyle/e corro o seguinte comando:

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

Se eu ligar process.cwd(), eu entendo /home/kyle/, não /home/kyle/some/dir/. Existe uma maneira de obter esse diretório?

Kyle Slattery
fonte
6
nodejs.org/docs/latest/api/globals.html o link da documentação da resposta aceita.
allenhwkim

Respostas:

1393

Encontrei depois de examinar a documentação novamente. O que eu estava procurando eram o __filenamee __dirnamevariáveis de nível de módulo.

  • __filenameé o nome do arquivo do módulo atual. Este é o caminho absoluto resolvido do arquivo de módulo atual. (ex: /home/kyle/some/dir/file.js)
  • __dirnameé o nome do diretório do módulo atual. (ex: /home/kyle/some/dir)
Kyle Slattery
fonte
3
Se você deseja apenas o nome do diretório e não o caminho completo, faça algo assim: function getCurrentDirectoryName () {var fullPath = __dirname; caminho var = fullPath.split ('/'); var cwd = caminho [path.length-1]; retornar cwd; }
Anthony Martin
58
@AnthonyMartin __dirname.split ("/"). Pop ()
19h
6
Para aqueles que tentam a solução @apx (como eu fiz :), essa solução não funciona no Windows.
Laoujin
36
Ou simplesmente__dirname.split(path.sep).pop()
Burgi
47
Ourequire('path').basename(__dirname);
Vyacheslav Cotruta
251

Então, basicamente, você pode fazer isso:

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

Use resolve () em vez de concatenar com '/' ou '\', caso contrário, você terá problemas entre plataformas.

Nota: __dirname é o caminho local do módulo ou script incluído. Se você está escrevendo um plugin que precisa conhecer o caminho do script principal, é:

require.main.filename

ou, para obter apenas o nome da pasta:

require('path').dirname(require.main.filename)
Marc
fonte
16
Se seu objetivo é apenas analisar e interagir com o arquivo json, é possível fazer isso com mais facilidade por meio de var settings = require('./settings.json'). Obviamente, é IO síncrona do fs, portanto, não faça isso em tempo de execução, mas no momento da inicialização está bom e, uma vez carregado, será armazenado em cache.
Isaacs
2
@ Marc Thanks! Por um tempo, agora eu estava tentando entender o fato de que __dirname é local para cada módulo. Eu tenho uma estrutura aninhada na minha biblioteca e preciso conhecer em vários lugares a raiz do meu aplicativo. Ainda bem que eu sei como fazer isso agora: D
Thijs Koerselman
Nó V8: path.dirname (process.mainModule.filename)
wayofthefuture
Se você não considera o Windows uma plataforma real, podemos pular a resolução? BSD, Macos, linux, tizen, symbian, Solaris, andróide, vibração, webos todos usam / certo?
Ray Foss
119

Este comando retorna o diretório atual:

var currentPath = process.cwd();

Por exemplo, para usar o caminho para ler o arquivo:

var fs = require('fs');
fs.readFile(process.cwd() + "\\text.txt", function(err, data)
{
    if(err)
        console.log(err)
    else
        console.log(data.toString());
});
Masoud Siahkali
fonte
Para aqueles que não entendia assíncrona e síncrona , consulte este link ... stackoverflow.com/a/748235/5287072
DarckBlezzer
16
é exatamente isso que o OP não deseja ... a solicitação é para o caminho do script executável!
caesarsol
3
O diretório atual é uma coisa muito diferente. Se você executar algo como cd /foo; node bar/test.js, o diretório atual seria /foo, mas o script está localizado em /foo/bar/test.js.
Rjmunro 5/07
Não é uma boa resposta. É uma bagunça uma lógica, pois esse pode ser um caminho muito mais curto do que o esperado.
kris_IV
Por que você faria isso; se o arquivo fosse relativo ao diretório atual, você pode apenas ler text.txte ele iria trabalhar, você não precisa para construir o caminho absoluto
Michael Mrozek
104

Use __dirname !!

__dirname

O nome do diretório do módulo atual. É o mesmo que o path.dirname () do __filename.

Exemplo: executando o nó example.js de / Users / mjr

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

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

Para ESModules, você desejaria usar: import.meta.url

DDD
fonte
1
Isso também sobrevive aos links simbólicos. Portanto, se você criar uma lixeira e precisar encontrar um arquivo, por exemplo, path.join (__ dirname, "../example.json"); ele ainda funciona quando o binário é ligado em node_modules / bin
Jason
2
Essa resposta não só foi dada anos antes, mas também não funciona mais com os módulos ES .
Dan Dascalescu
48

Quando se trata do script principal, é tão simples quanto:

process.argv[1]

A partir da documentação Node.js :

process.argv

Uma matriz contendo os argumentos da linha de comando. O primeiro elemento será 'node', o segundo elemento será o caminho para o arquivo JavaScript . Os próximos elementos serão quaisquer argumentos adicionais da linha de comando.

Se você precisar conhecer o caminho de um arquivo de módulo, use __filename .

Lukasz Wiktor
fonte
3
O downvoter poderia explicar por que isso não é recomendado?
Tamlyn
1
@Tamlyn Talvez porque process.argv[1]se aplique apenas ao script principal enquanto __filenameaponta para o arquivo do módulo que está sendo executado. Eu atualizo minha resposta para enfatizar a diferença. Ainda assim, não vejo nada de errado em usar process.argv[1]. Depende dos requisitos.
Lukasz Wiktor
10
Se o script principal foi iniciado com um gerenciador de processos de nó, como pm2 process.argv [1], apontará para o executável do gerenciador de processos /usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js
user3002996
34

O Node.js 10 suporta módulos ECMAScript , onde __dirnamee __filenamenão estão mais disponíveis .

Então, para obter o caminho para o módulo ES atual, é necessário usar:

import { fileURLToPath } from 'url';

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

E para o diretório que contém o módulo atual:

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

const __dirname = dirname(fileURLToPath(import.meta.url));
GOTO 0
fonte
Como saber se estou escrevendo um módulo ES ou não? É apenas uma questão de qual versão do Nó estou executando ou se estou usando palavras-chave de importação / exportação?
Ed Ednnin 18/04/19
2
Módulos ES disponíveis apenas com --experimental-modulessinalizador.
Nickensoul
1
--experimental-modules será necessário apenas se você estiver executando a versão do nó <13.2. apenas nomeie o arquivo .mjs em vez de .js
Brent
28
var settings = 
    JSON.parse(
        require('fs').readFileSync(
            require('path').resolve(
                __dirname, 
                'settings.json'),
            'utf8'));
foobar
fonte
7
Apenas uma observação, a partir do nó 0.5, você pode apenas solicitar um arquivo JSON. Claro que isso não responderia à pergunta.
Kevin Cox
1
__dirname não funciona mais com módulos ES .
Dan Dascalescu
24

Todo programa Node.js. possui algumas variáveis ​​globais em seu ambiente, o que representa algumas informações sobre o seu processo e uma delas __dirname.

Hazarapet Tunanyan
fonte
Essa resposta não só foi dada anos antes, como __dirname não funciona mais com os módulos ES .
Dan Dascalescu
É sobre NodeJS 10, mas esta resposta foi publicado em 2016.
Hazarapet Tunanyan
Eu sei. As respostas podem ser atualizadas conforme a tecnologia muda.
Dan Dascalescu
13

Sei que isso é bastante antigo, e a pergunta original à qual eu estava respondendo está marcada como duplicada e direcionada aqui, mas encontrei um problema ao tentar fazer com que os repórteres de jasmim funcionassem e não gostei da ideia de ter que fazer o downgrade ordem para que ele funcione. Descobri que o jasmine-repórteres não estava resolvendo o savePath corretamente e, na verdade, estava colocando a saída da pasta de relatórios no diretório jasmine-repórteres, em vez do diretório raiz do local onde executei o gulp. Para fazer isso funcionar corretamente, acabei usando process.env.INIT_CWD para obter o Diretório de trabalho atual inicial, que deve ser o diretório em que você executou o gulp. Espero que isso ajude alguém.

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

Você pode usar process.env.PWD para obter o caminho atual da pasta do aplicativo.

AbiSivam
fonte
2
O OP solicita o "caminho para o script" solicitado. PWD, que significa algo como Process Working Directory, não é isso. Além disso, a expressão "aplicativo atual" é enganosa.
dmcontador 8/09/17
7

Se você estiver usando pkgpara empacotar seu aplicativo, achará útil esta expressão:

appDirectory = require('path').dirname(process.pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));
  • process.pkginforma se o aplicativo foi compactado por pkg.

  • process.execPathmantém o caminho completo do executável, que é /usr/bin/nodeou semelhante para invocações diretas de scripts ( node test.js) ou do aplicativo empacotado.

  • require.main.filename mantém o caminho completo do script principal, mas fica vazio quando o Node é executado no modo interativo.

  • __dirnamecontém o caminho completo do script atual , então não o estou usando (embora possa ser o que o OP pede; então é melhor usar appDirectory = process.pkg ? require('path').dirname(process.execPath) : (__dirname || require('path').dirname(process.argv[0]));observando que no modo interativo __dirnameestá vazio.

  • Para o modo interativo, use process.argv[0]para obter o caminho para o executável do Nó ou process.cwd()para obter o diretório atual.

dmcontador
fonte
3

Use o basenamemétodo do pathmódulo:

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

Aqui está a documentação da qual o exemplo acima foi retirado.

Como Dan apontou, o Node está trabalhando nos módulos ECMAScript com o sinalizador "--experimental-modules". O nó 12 ainda suporta __dirnamee__filename como acima.


Se você estiver usando a --experimental-modulesbandeira, existe uma abordagem alternativa .

A alternativa é obter o caminho para o módulo ES atual :

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

E para o diretório que contém o módulo atual:

import path from 'path';

const __dirname = path.dirname(new URL(import.meta.url).pathname);
Michael Cole
fonte
-2

Se você quiser algo mais como $ 0 em um script de shell, tente o seguinte:

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;
    }
}
dmayo3
fonte
__dirnamee não__filename estão mais disponíveis com os módulos ES .
Dan Dascalescu