node.js - ¿Qué hace exactamente "/ usr/bin/env node" al comienzo de los archivos de nodo?
shebang (3)
Los scripts que debe ejecutar un intérprete normalmente tienen una línea shebang en la parte superior para indicarle al sistema operativo cómo ejecutarlos.
Si tiene un script llamado
foo
cuya primera línea es
#!/bin/sh
, el sistema leerá esa primera línea y ejecutará el equivalente de
/bin/sh foo
.
Debido a esto, la mayoría de los intérpretes están configurados para aceptar el nombre de un archivo de script como argumento de línea de comandos.
El nombre del intérprete después del
#!
tiene que ser un camino completo;
el sistema operativo no buscará su
$PATH
para encontrar el intérprete.
Si tiene que ejecutar un script por
node
, la forma obvia de escribir la primera línea es:
#!/usr/bin/node
pero eso no funciona si el comando de
node
no está instalado en
/usr/bin
.
Una solución común es usar el comando
env
(que en
realidad
no fue diseñado para este propósito):
#!/usr/bin/env node
Si su script se llama
foo
, el sistema operativo hará el equivalente de
/usr/bin/env node foo
El comando
env
ejecuta otro comando cuyo nombre se da en su línea de comando, pasando los siguientes argumentos a ese comando.
La razón por la que se usa aquí es que
env
buscará
$PATH
para el comando.
Entonces, si el
node
está instalado en
/usr/local/bin/node
, y tiene
/usr/local/bin
en su
$PATH
, el comando
env
invocará
/usr/local/bin/node foo
.
El objetivo principal del comando
env
es ejecutar otro comando con un entorno modificado, agregando o eliminando variables de entorno especificadas antes de ejecutar el comando.
Pero sin argumentos adicionales, solo ejecuta el comando con un entorno sin cambios, que es todo lo que necesita en este caso.
Hay algunos inconvenientes en este enfoque.
La mayoría de los sistemas modernos tipo Unix tienen
/usr/bin/env
, pero trabajé en sistemas más antiguos donde el comando
env
estaba instalado en un directorio diferente.
Puede haber limitaciones en argumentos adicionales que puede pasar usando este mecanismo.
Si el usuario
no
tiene el directorio que contiene el comando del
node
en
$PATH
, o tiene algún comando diferente llamado
node
, entonces podría invocar el comando incorrecto o no funcionar en absoluto.
Otros enfoques son:
-
Use un
#!
línea que especifica la ruta completa al comando delnode
sí, actualizando el script según sea necesario para diferentes sistemas; o -
Invoca el comando de
node
con tu script como argumento.
Consulte también
esta pregunta
(y
mi respuesta
) para obtener más información sobre el truco
#!/usr/bin/env
.
Por cierto, en mi sistema (Linux Mint 17.2), está instalado como
/usr/bin/nodejs
.
Según mis notas, cambió de
/usr/bin/node
a
/usr/bin/nodejs
entre Ubuntu 12.04 y 12.10.
El truco
#!/usr/bin/env
no ayudará con eso (a menos que configure un enlace simbólico o algo similar).
ACTUALIZACIÓN: Un comentario de mtraceur dice (reformateado):
Una solución para el problema nodejs vs nodo es iniciar el archivo con las siguientes seis líneas:
#!/bin/sh - '':'' /*- test1=$(nodejs --version 2>&1) && exec nodejs "$0" "$@" test2=$(node --version 2>&1) && exec node "$0" "$@" exec printf ''%s/n'' "$test1" "$test2" 1>&2 */
Esto primero intentará
nodejs
y luego intentaránode
, e imprimirá solo los mensajes de error si no se encuentran ambos. Una explicación está fuera del alcance de estos comentarios, solo la dejo aquí en caso de que ayude a alguien a lidiar con el problema ya que esta respuesta trajo el problema.
No he usado NodeJS últimamente.
Espero que el problema
nodejs
se haya resuelto en los años transcurridos desde que publiqué esta respuesta por primera vez.
En Ubuntu 18.04, el paquete
nodejs
instala
/usr/bin/nodejs
como un enlace simbólico a
/usr/bin/node
.
En algunos SO anteriores (Ubuntu o Linux Mint, no estoy seguro de cuál), había un paquete
nodejs-legacy
que proporcionaba el
node
como un enlace simbólico a
nodejs
.
No garantizo que tenga todos los detalles correctos.
Había visto esta línea
#!/usr/bin/env node
al comienzo de algunos ejemplos en
nodejs
y busqué en Google sin encontrar ningún tema que pudiera responder a la razón de esa línea.
La naturaleza de las palabras hace que la búsqueda no sea tan fácil.
Había leído recientemente algunos libros de
javascript
y
nodejs
y no recordaba haberlo visto en ninguno de ellos.
Si quieres un ejemplo, puedes ver el
tutorial
oficial de
RabbitMQ
, lo tienen en casi todos sus ejemplos, aquí está uno de ellos:
#!/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);
});
¿Podría alguien explicarme cuál es el significado de esta línea?
¿Cuál es la diferencia si pongo o elimino esta línea? ¿En qué casos lo necesito?
Respuesta corta: es el camino hacia el intérprete.
EDITAR (respuesta larga): la razón por la que no hay una barra inclinada antes de "nodo" es porque no siempre se puede garantizar la fiabilidad de #! / Bin /. El bit "/ env" hace que el programa sea más multiplataforma al ejecutar el script en un entorno modificado y poder encontrar de manera más confiable el programa de intérprete.
No necesariamente lo necesita, pero es bueno usarlo para garantizar la portabilidad (y la profesionalidad)
#!/usr/bin/env node
es
una instancia de una
línea shebang
: la
primera línea en un archivo ejecutable de texto sin formato en
plataformas tipo Unix
que le dice al sistema a qué intérprete pasar ese archivo para su ejecución
, a través del comando línea siguiendo el
#!
mágico
#!
prefijo (llamado
shebang
).
Nota:
Windows
no
admite líneas shebang
, por lo que se
ignoran
efectivamente allí;
en Windows, es únicamente la
extensión
del
nombre
de archivo de un
archivo
determinado lo que determina qué ejecutable lo interpretará.
Sin embargo, todavía los necesita en el contexto de
npm
.
[1]
La siguiente discusión general de las líneas shebang se limita a plataformas tipo Unix:
En la siguiente discusión, asumiré que el archivo que contiene el código fuente para la ejecución de Node.js simplemente se llama
file
.
-
NECESITA esta línea , si desea invocar un archivo fuente Node.js directamente , como un ejecutable por derecho propio; esto supone que el archivo ha sido marcado como ejecutable con un comando como
chmod +x ./file
, que luego le permite invocar el archivo con, por ejemplo,./file
o, si está ubicado en uno de los directorios listados en la variable$PATH
, simplemente comofile
.-
Específicamente, necesita una línea shebang para crear
CLI
basadas en archivos fuente Node.js como parte de un
paquete
npm, con las CLI que instalará
npm
según el valor de la clave"bin"
en el paquete de unpackage.json
archivopackage.json
; También vea esta respuesta sobre cómo funciona con los paquetes instalados globalmente . La nota al pie [1] muestra cómo se maneja esto en Windows.
-
Específicamente, necesita una línea shebang para crear
CLI
basadas en archivos fuente Node.js como parte de un
paquete
npm, con las CLI que instalará
-
NO necesita esta línea para invocar un archivo explícitamente a través del intérprete de
node
, por ejemplo,node ./file
Información de antecedentes opcional :
#!/usr/bin/env <executableName>
es una forma de especificar de forma
portátil
un intérprete: en pocas palabras, dice: ejecute
<executableName>
donde sea que (primero) lo encuentre entre los directorios listados en la variable
$PATH
(e implícitamente pasarle la ruta al archivo en cuestión).
Esto explica el hecho de que un intérprete determinado puede instalarse en diferentes ubicaciones a través de plataformas, que definitivamente es el caso con el
node
, el binario Node.js.
Por el contrario, se puede confiar en que la ubicación de la propia utilidad
env
se encuentra en la
misma
ubicación en todas las plataformas, a saber
/usr/bin/env
, y se
requiere
especificar la ruta
completa
a un ejecutable en una línea shebang.
Tenga en cuenta que la utilidad POSIX
env
se está
reutilizando
aquí para ubicar por nombre de archivo y ejecutar un ejecutable en
$PATH
.
El verdadero propósito de
env
es administrar el entorno para un comando: consulte
las especificaciones POSIX de
env
y
la útil respuesta de Keith Thompson
.
También vale la pena señalar que Node.js está haciendo una
excepción de
sintaxis para las líneas shebang, dado que no son códigos JavaScript válidos (
#
no es un carácter de comentario en JavaScript, a diferencia de los shells similares a POSIX y otros intérpretes).
[1] En aras de la coherencia multiplataforma,
npm
crea archivos
wrapper
*.cmd
(archivos por lotes) en Windows
al instalar ejecutables especificados en el archivo
package.json
un paquete (a través de la propiedad
"bin"
).
Básicamente, estos archivos por lotes de envoltura
imitan la
funcionalidad shebang de Unix:
invocan explícitamente el archivo de destino con el ejecutable especificado en la línea shebang
; por lo tanto,
sus scripts deben incluir una línea shebang incluso si solo tiene la intención de ejecutarlos en Windows
; vea
esta respuesta
mía para más detalles.
Dado que los archivos
*.cmd
pueden invocarse sin la extensión
.cmd
, esto
npm
una experiencia multiplataforma perfecta: tanto en Windows como en Unix puede invocar efectivamente una CLI
npm
en
npm
por su nombre original sin extensión.