node.js shebang

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 del node 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 como file .

    • 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 un package.json archivo package.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.
  • 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.