Había visto esta línea #!/usr/bin/env nodeal principio de algunos ejemplos en nodejsy 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 javascripty nodejsrecientemente 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?

nodenpminstalar un script fuente de Node.js como una CLI (potencialmente disponible a nivel mundial) , debe usar una línea shebang, enpmincluso hará que funcione en Windows; vea mi respuesta actualizada una vez más.Respuestas:
#!/usr/bin/env nodees 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,,./fileo, si está ubicado en uno de los directorios listados en la$PATHvariable, simplemente comofile.npmsegún el valor de la"bin"clave en elpackage.jsonarchivo 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
nodeintérprete, por ejemplo,node ./fileInformació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$PATHvariable (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
nodedel binario Node.js.Por el contrario,
envse 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
envse está reutilizando aquí para ubicarla por nombre de archivo y ejecutar un ejecutable en formato$PATH.El verdadero propósito de
enves administrar el entorno para un comando; consulteenvla 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,
npmcrea archivos de envoltura*.cmd(archivos por lotes) en Windows al instalar ejecutables especificados en elpackage.jsonarchivo 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
*.cmdarchivos se pueden invocar sin la.cmdextensión, esto lo convierte en una experiencia multiplataforma perfecta: tanto en Windows como en Unix, puede invocar efectivamente unanpmCLI instalada por su nombre original sin extensión.fuente
.cmdy.pydeterminan qué programa se utilizará para ejecutar dichos archivos. En Unix, la línea shebang realiza esa función. Para quenpmfuncione 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
foocuyo 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$PATHinté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
nodecomando no está instalado en/usr/bin.Una solución alternativa común es usar el
envcomando (que no era realmente destinado a este propósito):Si se llama a su script
foo, el sistema operativo hará el equivalente aEl
envcomando 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 queenvbuscará$PATHel comando. Entonces, sinodeestá instalado/usr/local/bin/nodey tiene/usr/local/binen su$PATH, elenvcomando se invocará/usr/local/bin/node foo.El propósito principal del
envcomando 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 elenvcomando 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 elnodecomando$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 alnodecomando en sí, actualizando el script según sea necesario para diferentes sistemas; onodecomando 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/envtruco.Por cierto, en mi sistema (Linux Mint 17.2), está instalado como
/usr/bin/nodejs. Según mis notas, cambió de/usr/bin/nodea/usr/bin/nodejsentre Ubuntu 12.04 y 12.10. los#!/usr/bin/envtruco 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
nodejsvs.nodese haya resuelto en los años desde que publiqué esta respuesta por primera vez. En Ubuntu 18.04, elnodejspaquete se instala/usr/bin/nodejscomo 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-legacypaquete que se proporcionabanodecomo enlace simbólico anodejs. No hay garantía de que tenga todos los detalles correctos.fuente
nodejsvsnodees 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>&26)*/. Esto primero intentaránodejsy 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 nuevonodecomo 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 apoyanodeuna vez Debian hizo).-xy-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/envbroca 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$PATHpara encontrarlo. El punto es que la#!línea requiere la ruta completa al comando que se invoca, y no necesariamente sabe dóndenodeestá instalado.