¿Qué hace exactamente “/ usr / bin / env node” al principio de los archivos de nodo?

Había visto esta línea #!/usr/bin/env node al comienzo de algunos ejemplos en nodejs y había buscado 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 buscarlo no sea tan fácil.

Leí algunos libros de javascript y nodejs recientemente y no recuerdo haberlos visto en ninguno de ellos.

Si quieres un ejemplo, puedes ver el tutorial oficial de RabbitMQ , lo tienen en casi todos sus ejemplos, aquí hay 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 quito esta línea? ¿En qué casos lo necesito?

#!/usr/bin/env node es una instancia de una línea shebang : la primera línea en un archivo de texto plano ejecutable en plataformas similares a Unix que le dice al sistema a qué intérprete debe pasar ese archivo para su ejecución , a través del comando línea siguiendo la magia #! prefijo (llamado shebang ).

Nota: Windows no admite líneas shebang , por lo que efectivamente se ignoran allí; en Windows es solo la extensión del nombre de archivo de un archivo dado 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 de shebang se limita a plataformas similares a Unix:

En la siguiente discusión, asumiré que el archivo que contiene el código fuente para su ejecución por Node.js se denomina simplemente file .

  • NECESITA esta línea , si desea invocar un archivo de origen Node.js directamente , como un ejecutable por derecho propio: esto supone que el archivo se ha 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 como file .

    • Específicamente, necesita una línea shebang para crear CLI basadas en los archivos de origen Node.js como parte de un paquete npm, con las CLI que se instalarán por npm función del valor de la clave "bin" en el paquete de un package.json archivo package.json ; También vea esta respuesta para saber cómo funciona con los paquetes instalados globalmente . La nota al pie [1] muestra cómo se maneja esto en Windows.
  • NO necesita esta línea para invocar un archivo explícitamente a través del intérprete del node , por ejemplo, node ./file


Información de fondo opcional :

#!/usr/bin/env es una forma de especificar de manera portátil un intérprete: en pocas palabras, dice: ejecute Nombre de archivo de ejecución donde quiera que (primero) lo encuentre entre los directorios listados en la variable $PATH (e implícitamente pásale 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, lo 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 utilidad env esté 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 de shebang.

Tenga en cuenta que la utilidad de POSIX env se está reutilizando aquí para ubicar por nombre de archivo y ejecutar un archivo 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 syntax 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 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" ). Esencialmente, estos archivos por lotes de envoltura 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 mio para detalles
Dado que los archivos *.cmd pueden invocarse sin la extensión .cmd , esto se npm una experiencia multiplataforma sin problemas: tanto en Windows como en Unix puede invocar efectivamente una CLI npm por su nombre original, sin extensión.

Los scripts que deben ser ejecutados por un intérprete normalmente tienen una línea shebang en la parte superior para indicar 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 un argumento de línea de comando.

El nombre del intérprete después de #! tiene que ser un camino completo; el sistema operativo no buscará en su $PATH para encontrar el intérprete.

Si tiene un script para ser ejecutado por un 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 aparece en su línea de comandos, 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 usted tiene /usr/local/bin en su $PATH , el comando env invocará /usr/local/bin/node foo .

El propósito 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, simplemente ejecuta el comando con un entorno sin cambios, que es todo lo que necesita en este caso.

Hay algunos inconvenientes de 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 se instaló en un directorio diferente. Puede haber limitaciones en los argumentos adicionales que puede pasar utilizando este mecanismo. Si el usuario no tiene el directorio que contiene el comando de 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:

  • Utilice un #! línea que especifica la ruta completa al comando del node , actualizando el script según sea necesario para diferentes sistemas; o
  • Invoque el comando de node con su script como argumento.

Vea también esta pregunta (y mi respuesta ) para una discusión más #!/usr/bin/env 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).

Respuesta corta: Es el camino al 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 progtwig sea más multiplataforma ejecutando el script en un entorno modificado y pudiendo encontrar de manera más confiable el progtwig de intérprete.

No necesariamente lo necesita, pero es bueno usarlo para garantizar la portabilidad (y la profesionalidad)