Había visto esta línea #!/usr/bin/env node
al principio de algunos ejemplos en nodejs
y busqué en Google sin encontrar ningún tema que pudiera responder el motivo de esa línea.
La naturaleza de las palabras hace que la búsqueda no sea tan fácil.
Leí algunos libros javascript
y nodejs
recientemente y no recordaba haberlos visto en ninguno de ellos.
Si quieres un ejemplo, puedes ver el tutorialRabbitMQ
oficial , lo tienen en casi todos sus ejemplos, aquí tienes 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);
});
¿Alguien podría explicarme cuál es el significado de esta línea?
¿Cuál es la diferencia si pongo o quito esta línea? ¿En que casos lo necesito?
node
npm
instalar un script fuente de Node.js como una CLI (potencialmente disponible a nivel mundial) , debe usar una línea shebang, enpm
incluso hará que funcione en Windows; vea mi respuesta actualizada una vez más.Respuestas:
#!/usr/bin/env node
es una instancia de una línea shebang : la primera línea en un archivo ejecutable de texto plano en plataformas similares a Unix que le dice al sistema a qué intérprete pasar ese archivo para su ejecución , a través de la línea de comando que sigue al#!
prefijo mágico (llamado shebang ) .Nota: en Windows no no admite shebang líneas , por lo que están efectivamente ignorados 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, aún los necesita en el contexto de
npm
. [1]La siguiente discusión general de las líneas shebang se limita a plataformas similares a Unix:
En la siguiente discusión asumiré que el archivo que contiene el código fuente para ser ejecutado por Node.js simplemente se nombra
file
.Usted NECESITA esta línea , si desea invocar un archivo de origen Node.js directamente , como un archivo ejecutable en su propio derecho - esto supone que el archivo se ha marcado como ejecutable con un comando como
chmod +x ./file
, que a su vez le permite invocar el archivo con, por ejemplo,,./file
o, si está ubicado en uno de los directorios listados en la$PATH
variable, simplemente comofile
.npm
según el valor de la"bin"
clave en elpackage.json
archivo de un paquete ; también vea esta respuesta para saber cómo funciona con paquetes instalados globalmente . La nota al pie [1] muestra cómo se maneja esto en Windows.Usted NO necesita esta línea para invocar un archivo de forma explícita a través del
node
intérprete, por ejemplo,node ./file
Información de antecedentes opcional :
#!/usr/bin/env <executableName>
es una forma de especificar un intérprete de forma portátil : en pocas palabras, dice: ejecutar<executableName>
donde (primero) lo encuentre entre los directorios enumerados en la$PATH
variable (y pasarle implícitamente la ruta al archivo en cuestión).Esto explica el hecho de que un intérprete determinado puede instalarse en diferentes ubicaciones en todas las plataformas, lo que definitivamente es el caso
node
del binario Node.js.Por el contrario,
env
se puede confiar en que la ubicación de la utilidad en sí está en la misma ubicación en todas las plataformas, es decir/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 ubicarla por nombre de archivo y ejecutar un ejecutable en formato$PATH
.El verdadero propósito de
env
es administrar el entorno para un comando; consulteenv
la especificación POSIX 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 un código JavaScript válido (
#
no es un carácter de comentario en JavaScript, a diferencia de las shells similares a POSIX y otros intérpretes).[1] En aras de la coherencia entre plataformas,
npm
crea archivos de envoltura*.cmd
(archivos por lotes) en Windows al instalar ejecutables especificados en elpackage.json
archivo de un paquete (a través de la"bin"
propiedad). Esencialmente, estos archivos por lotes de contenedor imitan la funcionalidad shebang de Unix: invocan el archivo de destino explícitamente 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
*.cmd
archivos se pueden invocar sin la.cmd
extensión, esto lo convierte en una experiencia multiplataforma perfecta: tanto en Windows como en Unix, puede invocar efectivamente unanpm
CLI instalada por su nombre original sin extensión.fuente
.cmd
y.py
determinan qué programa se utilizará para ejecutar dichos archivos. En Unix, la línea shebang realiza esa función. Para quenpm
funcione en todas las plataformas compatibles, necesita la línea shebang incluso en Windows.Los scripts que deben ser ejecutados por 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
cuyo primera línea#!/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 secuencia de comandos como argumento de línea de comandos.El nombre del intérprete que sigue al
#!
a debe ser una ruta completa; el sistema operativo no buscará su$PATH
intérprete.Si tiene un script para que lo ejecute
node
, la forma obvia de escribir la primera línea es:pero eso no funciona si el
node
comando no está instalado en/usr/bin
.Una solución alternativa común es usar el
env
comando (que no era realmente destinado a este propósito):Si se llama a su script
foo
, el sistema operativo hará el equivalente aEl
env
comando 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 queenv
buscará$PATH
el comando. Entonces, sinode
está instalado/usr/local/bin/node
y tiene/usr/local/bin
en su$PATH
, elenv
comando se invocará/usr/local/bin/node foo
.El propósito principal del
env
comando es ejecutar otro comando con un entorno modificado, agregando o eliminando variables de entorno especificadas antes de ejecutar el comando. Pero sin argumentos adicionales, simplemente 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 lo han hecho
/usr/bin/env
, pero trabajé en sistemas más antiguos donde elenv
comando se instaló en un directorio diferente. Puede haber limitaciones en los argumentos adicionales que puede pasar usando este mecanismo. Si el usuario no tiene el directorio que contiene elnode
comando$PATH
, o tiene un comando diferente llamadonode
, entonces podría invocar el comando incorrecto o no funcionar en absoluto.Otros enfoques son:
#!
línea que especifique la ruta completa alnode
comando en sí, actualizando el script según sea necesario para diferentes sistemas; onode
comando con su secuencia de comandos como argumento.Consulte también esta pregunta (y mi respuesta ) para obtener más información sobre la
#!/usr/bin/env
truco.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. los#!/usr/bin/env
truco no ayudará con eso (a menos que configure un enlace simbólico o algo similar).ACTUALIZACIÓN: Un comentario de mtraceur dice (reformateado):
No he usado NodeJS últimamente. Mi esperanza es que el problema de
nodejs
vs.node
se haya resuelto en los años desde que publiqué esta respuesta por primera vez. En Ubuntu 18.04, elnodejs
paquete se instala/usr/bin/nodejs
como un enlace simbólico a/usr/bin/node
. En algunos sistemas operativos anteriores (Ubuntu o Linux Mint, no estoy seguro de cuál), había unnodejs-legacy
paquete que se proporcionabanode
como enlace simbólico anodejs
. No hay garantía de que tenga todos los detalles correctos.fuente
nodejs
vsnode
es iniciar el archivo con las siguientes seis líneas: 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)*/
. Esto primero intentaránodejs
y luego intentaránode
, y solo imprimirá 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 planteó el problema.-
en la#!
línea?-
in#!/bin/sh -
es solo un hábito que asegura que el shell se comporte correctamente en el conjunto de circunstancias extremadamente estrechas e improbables en las que el nombre del script o la ruta relativa que el shell ve comienza con-
. (Además, sí, parece que todas las distribuciones principales habían convergido de nuevonode
como el nombre principal. No fui a investigar para verificar cuando hice mi comentario, pero por lo que sé, solo el árbol genealógico de la distribución Debian utilizadonodejs
, y parece al igual que todos vuelven a los que también apoyanode
una vez Debian hizo).-x
y-v
", pero dado que los primeros me gusta de Bourne solo analizaron el primer argumento como opciones posibles, y dado que el shell comienza con esas opciones desactivadas , era abusivo hacer que el shell no intentara analizar el nombre del script desde el original y, por lo tanto, sigue siendo abusable porque el comportamiento se mantiene en los modernos Bourne-like por razones de compatibilidad. Si recuerdo bien toda mi historia de Bourne y trivia de portabilidad.Respuesta corta: es el camino hacia el intérprete.
EDITAR (Respuesta larga): La razón por la que no hay una barra diagonal antes de "nodo" es porque no siempre se puede garantizar la confiabilidad de #! / Bin /. El bit "/ env" hace que el programa sea más multiplataforma al ejecutar el script en un entorno modificado y poder encontrar el programa intérprete de manera más confiable.
No necesariamente lo necesita, pero es bueno usarlo para garantizar la portabilidad (y la profesionalidad)
fuente
/usr/bin/env
broca no modifica el entorno. Es solo un comando en una ubicación (en su mayoría) conocida que invoca otro comando dado como argumento y busca$PATH
para encontrarlo. El punto es que la#!
línea requiere la ruta completa al comando que se invoca, y no necesariamente sabe dóndenode
está instalado.