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
.
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:
#!
línea que especifica la ruta completa al comando del node
, actualizando el script según sea necesario para diferentes sistemas; o 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)