Eu tinha visto esta linha #!/usr/bin/env node
no início de alguns exemplos em nodejs
e pesquisei no Google sem encontrar nenhum tópico que pudesse responder o motivo daquela linha.
A natureza das palavras torna a pesquisa não tão fácil.
Eu tinha lido alguns javascript
e nodejs
livros recentemente e não me lembrava de ter visto isso em nenhum deles.
Se você quiser um exemplo, pode ver o tutorialRabbitMQ
oficial , eles o têm em quase todos os seus exemplos, aqui está um deles:
#!/usr/bin/env node
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var ex = 'logs';
var msg = process.argv.slice(2).join(' ') || 'Hello World!';
ch.assertExchange(ex, 'fanout', {durable: false});
ch.publish(ex, '', new Buffer(msg));
console.log(" [x] Sent %s", msg);
});
setTimeout(function() { conn.close(); process.exit(0) }, 500);
});
Alguém poderia me explicar qual é o significado desta linha?
Qual é a diferença se eu colocar ou remover esta linha? Em que casos eu preciso disso?
node
npm
instalar um script de origem Node.js como um CLI (potencialmente disponível globalmente) , você deve usar uma linha shebang - enpm
até fará com que funcione no Windows; veja minha resposta mais uma vez atualizada.Respostas:
#!/usr/bin/env node
é uma instância de uma linha shebang : a primeira linha em um arquivo de texto simples executável em plataformas do tipo Unix que informa ao sistema para qual intérprete passar esse arquivo para execução , através da linha de comando seguindo o#!
prefixo mágico (chamado shebang ) .Observação: o Windows não oferece suporte a linhas shebang , portanto, elas são efetivamente ignoradas lá; no Windows, é apenas a extensão de nome de arquivo de um determinado arquivo que determina qual executável o interpretará. No entanto, você ainda precisa deles no contexto de
npm
. [1]A seguir, a discussão geral de linhas shebang é limitada a plataformas do tipo Unix:
Na discussão a seguir, assumirei que o arquivo que contém o código-fonte para execução pelo Node.js é simplesmente nomeado
file
.Você PRECISA desta linha , se quiser invocar um arquivo de origem Node.js diretamente , como um executável por si só - isso pressupõe que o arquivo foi marcado como executável com um comando como
chmod +x ./file
, que permite invocar o arquivo com, por exemplo,,./file
ou, se estiver localizado em um dos diretórios listados na$PATH
variável, simplesmente comofile
.npm
base no valor da"bin"
chave em umpackage.json
arquivo de pacote ; também veja esta resposta para saber como isso funciona com pacotes instalados globalmente . A nota de rodapé [1] mostra como isso é tratado no Windows.Você NÃO precisa desta linha para invocar um arquivo explicitamente por meio do
node
interpretador, por exemplo,node ./file
Informações básicas opcionais :
#!/usr/bin/env <executableName>
é uma forma de especificar portavelmente um interpretador: em poucas palavras, ele diz: execute<executableName>
onde quer que você (primeiro) o encontre entre os diretórios listados na$PATH
variável (e passe implicitamente o caminho para o arquivo em questão).Isso explica o fato de que um determinado intérprete pode ser instalado em diferentes locais nas plataformas, o que é definitivamente o caso
node
do binário Node.js.Em contraste, a localização do
env
próprio utilitário pode ser considerada no mesmo local em todas as plataformas, a saber/usr/bin/env
- e especificar o caminho completo para um executável é necessário em uma linha shebang.Observe que o utilitário POSIX
env
está sendo reaproveitado aqui para localizar por nome de arquivo e executar um executável no$PATH
.O verdadeiro propósito de
env
é gerenciar o ambiente para um comando - vejaenv
as especificações POSIX e a resposta útil de Keith Thompson .Também é importante notar que o Node.js está abrindo uma exceção de sintaxe para linhas shebang, visto que elas não são código JavaScript válido (
#
não é um caractere de comentário em JavaScript, ao contrário de shells semelhantes a POSIX e outros interpretadores).[1] No interesse da consistência de plataforma cruzada,
npm
cria arquivos wrapper*.cmd
(arquivos em lote) no Windows ao instalar executáveis especificados em umpackage.json
arquivo de pacote (por meio da"bin"
propriedade). Essencialmente, esses arquivos em lote de wrapper imitam a funcionalidade shebang do Unix: eles invocam o arquivo de destino explicitamente com o executável especificado na linha shebang - portanto, seus scripts devem incluir uma linha shebang mesmo se você pretende executá-los apenas no Windows - veja esta resposta meu para obter detalhes.Uma vez que os
*.cmd
arquivos podem ser chamados sem o.cmd
extensão, isso contribui para uma experiência de plataforma cruzada perfeita: no Windows e no Unix, você pode invocar com eficácia umanpm
CLI instalada por seu nome original sem extensão.fonte
.cmd
e.py
determinam qual programa será usado para executar esses arquivos. No Unix, a linha shebang executa essa função. Para fazernpm
funcionar em todas as plataformas suportadas, você precisa da linha shebang mesmo no Windows.Os scripts que devem ser executados por um intérprete normalmente têm uma linha shebang na parte superior para informar ao SO como executá-los.
Se você tiver um script
foo
cujo nome é a primeira linha#!/bin/sh
, o sistema lerá essa primeira linha e executará o equivalente de/bin/sh foo
. Por causa disso, a maioria dos intérpretes são configurados para aceitar o nome de um arquivo de script como um argumento de linha de comando.O nome do intérprete após o
#!
deve ser um caminho completo; o sistema operacional não pesquisará o seu$PATH
para encontrar o intérprete.Se você tiver um script para ser executado
node
, a maneira óbvia de escrever a primeira linha é:mas isso não funciona se o
node
comando não estiver instalado em/usr/bin
.Uma solução alternativa comum é usar o
env
comando (que não foi realmente projetado para essa finalidade):Se o seu script for chamado
foo
, o sistema operacional fará o equivalente aO
env
comando executa outro comando cujo nome é fornecido em sua linha de comando, passando todos os argumentos a seguir para esse comando. O motivo pelo qual ele é usado aqui é paraenv
pesquisar$PATH
o comando. Portanto, senode
estiver instalado/usr/local/bin/node
e você tiver/usr/local/bin
no seu$PATH
, oenv
comando será invocado/usr/local/bin/node foo
.O objetivo principal do
env
comando é executar outro comando com um ambiente modificado, adicionando ou removendo variáveis de ambiente especificadas antes de executar o comando. Mas sem argumentos adicionais, ele apenas executa o comando com um ambiente inalterado, que é tudo de que você precisa neste caso.Existem algumas desvantagens nessa abordagem. A maioria dos sistemas modernos do tipo Unix
/usr/bin/env
sim, mas trabalhei em sistemas mais antigos, onde oenv
comando foi instalado em um diretório diferente. Pode haver limitações em argumentos adicionais que você pode passar usando este mecanismo. Se o usuário não tiver o diretório que contém onode
comando em$PATH
, ou se algum comando diferente for chamadonode
, ele poderá invocar o comando errado ou não funcionar.Outras abordagens são:
#!
linha que especifica o caminho completo para onode
próprio comando, atualizando o script conforme necessário para diferentes sistemas; ounode
comando com seu script como um argumento.Veja também esta pergunta (e minha resposta ) para mais discussão sobre o
#!/usr/bin/env
truque.Aliás, no meu sistema (Linux Mint 17.2), ele está instalado como
/usr/bin/nodejs
. De acordo com as minhas anotações, ele mudou de/usr/bin/node
que/usr/bin/nodejs
entre Ubuntu 12.04 e 12.10. O#!/usr/bin/env
truque não ajudará com isso (a menos que você configure um link simbólico ou algo semelhante).ATUALIZAÇÃO: Um comentário de mtraceur diz (reformatado):
Não tenho usado o NodeJS recentemente. Minha esperança é que o problema
nodejs
vs.node
tenha sido resolvido nos anos desde que publiquei esta resposta pela primeira vez. No Ubuntu 18.04, onodejs
pacote é instalado/usr/bin/nodejs
como um link simbólico para/usr/bin/node
. Em algum sistema operacional anterior (Ubuntu ou Linux Mint, não tenho certeza de qual), havia umnodejs-legacy
pacote fornecidonode
como um link simbólico paranodejs
. Nenhuma garantia de que tenha todos os detalhes corretos.fonte
nodejs
vsnode
é iniciar o arquivo com as seguintes seis linhas: 1)#!/bin/sh -
, 2)':' /*-
3)test1=$(nodejs --version 2>&1) && exec nodejs "$0" "$@"
4)test2=$(node --version 2>&1) && exec node "$0" "$@"
, 5)exec printf '%s\n' "$test1" "$test2" 1>&2
6)*/
. Isso tentará primeironodejs
e depois tentaránode
, e somente imprimirá as mensagens de erro se ambas não forem encontradas. Uma explicação está fora do escopo desses comentários, estou apenas deixando-a aqui para o caso de ajudar alguém a lidar com o problema, uma vez que esta resposta trouxe o problema à tona.-
na#!
linha?-
in#!/bin/sh -
é apenas um hábito que garante que o shell se comporte corretamente no conjunto extremamente estreito e improvável de circunstâncias em que o nome do script ou caminho relativo que o shell vê começa com um-
. (Além disso, sim, parece que todas as distro mainstream convergiram de volta paranode
o nome principal. Não me preocupei em verificar quando fiz meu comentário, mas, pelo que sei, apenas a árvore genealógica da distribuição Debian usadanodejs
, e parece como se todos eles voltassem ao suportenode
assim que o Debian fez.)-x
e-v
", mas como os primeiros gostos de Bourne analisavam apenas o primeiro argumento como opções possíveis, e como o shell começa com essas opções desativadas , era abusivo fazer com que o shell não tentasse analisar o nome do script desde o original e, portanto, permaneceria abusivo porque o comportamento é mantido em estilos Bourne modernos por motivos de compatibilidade. Se bem me lembro de toda a minha história Bourne e curiosidades sobre portabilidade, certo.Resposta curta: É o caminho para o intérprete.
EDIT (Resposta longa): O motivo de não haver nenhuma barra antes de "nó" é porque você nem sempre pode garantir a confiabilidade de #! / Bin /. O bit "/ env" torna o programa mais multiplataforma, executando o script em um ambiente modificado e sendo capaz de encontrar o programa interpretador de forma mais confiável.
Você não precisa necessariamente, mas é bom usar para garantir portabilidade (e profissionalismo)
fonte
/usr/bin/env
bit não modifica o ambiente. É apenas um comando em um local (principalmente) conhecido que invoca outro comando fornecido como um argumento e pesquisa$PATH
para encontrá-lo. O ponto é que a#!
linha requer o caminho completo para o comando que está sendo invocado e você não necessariamente sabe ondenode
está instalado.