Que fait exactement le noeud / usr / bin / env au début des fichiers de noeud?

J’avais vu cette ligne #!/usr/bin/env node au début de quelques exemples dans nodejs et j’avais googlé sans trouver aucun sujet pouvant répondre à la raison de cette ligne.

La nature des mots rend la recherche pas si facile.

J’avais lu des livres javascript et nodejs récemment et je ne me souvenais pas de l’avoir vu dans aucun d’entre eux.

Si vous voulez un exemple, vous pourriez voir le tutoriel officiel de RabbitMQ , ils l’ont dans presque tous leurs exemples, en voici un:

 #!/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); }); 

Quelqu’un pourrait-il m’expliquer quelle est la signification de cette ligne?

Quelle est la différence si je mets ou supprime cette ligne? Dans quels cas en ai-je besoin?

#!/usr/bin/env node est une instance d’une ligne shebang : la toute première ligne d’un fichier texte brut exécutable sur des plates-formes de type Unix qui indique au système quel interpréteur transmettre ce fichier pour exécution , via la commande ligne suivant le #! magique #! préfixe (appelé shebang ).

Remarque: Windows ne prend pas en charge les lignes shebang , elles y sont donc ignorées . sous Windows, c’est uniquement l’ extension du nom de fichier d’ un fichier donné qui détermine ce que l’exécutable va interpréter. Cependant, vous en avez toujours besoin dans le contexte de npm . [1]

La discussion générale suivante sur les lignes de shebang se limite aux plates-formes de type Unix:

Dans la discussion suivante, je suppose que le fichier contenant le code source à exécuter par Node.js est simplement nommé file .

  • Vous avez besoin de cette ligne , si vous voulez appeler directement un fichier source Node.js, en tant qu’exécutable à part entière – cela suppose que le fichier a été marqué comme exécutable avec une commande telle que chmod +x ./file , qui alors vous permet d’appeler le fichier avec, par exemple, ./file , ou, s’il est situé dans l’un des répertoires répertoriés dans la variable $PATH , simplement en tant que file .

    • Plus précisément, vous avez besoin d’une ligne shebang pour créer des CLI basées sur les fichiers sources Node.js dans le cadre d’un package npm, les CLI devant être installées par npm fonction de la clé "bin" dans le package d’un package.json fichier package.json ; voir également cette réponse pour savoir comment cela fonctionne avec les paquets installés globalement . La note [1] montre comment cela est géré sous Windows.
  • Vous n’avez pas besoin de cette ligne pour appeler un fichier explicitement via l’interpréteur de node , par exemple, node ./file


Informations d’arrière-plan facultatives :

#!/usr/bin/env est un moyen de spécifier un interprète de manière portable : en un mot, il dit: exécutez partout où vous l’avez trouvé parmi les répertoires listés dans la variable $PATH (et implicitement passer le chemin au fichier à scope de main).

Cela explique le fait qu’un interpréteur donné peut être installé à différents emplacements sur différentes plates-formes, ce qui est certainement le cas avec node , le binary Node.js.

En revanche, l’emplacement de l’utilitaire env lui-même peut se trouver au même endroit sur toutes les plates-formes, à savoir /usr/bin/env – et la spécification du chemin complet d’un exécutable est requirejse dans une ligne shebang.

Notez que l’utilitaire POSIX env est utilisé ici pour localiser par nom de fichier et exécuter un exécutable dans $PATH .
Le véritable objective de env est de gérer l’environnement pour une commande – voir les spécifications POSIX et la réponse utile de Keith Thompson .


Il est également intéressant de noter que Node.js fait une exception de syntaxe pour les lignes shebang, étant donné qu’elles ne sont pas du code JavaScript valide ( # n’est pas un caractère de commentaire dans JavaScript, contrairement aux shells de type POSIX et autres interpréteurs).


[1] Dans l’intérêt de la cohérence entre plates-formes, npm crée des fichiers wrapper *.cmd (fichiers de commandes) sous Windows lors de l’installation d’exécutables spécifiés dans le fichier package.json un package (via la propriété "bin" ). Essentiellement, ces fichiers batch wrapper imitent la fonctionnalité Unix shebang: ils invoquent explicitement le fichier cible avec l’exécutable spécifié dans la ligne shebangvos scripts doivent donc inclure une ligne shebang même si vous ne souhaitez les exécuter que sous Windows – voir cette réponse à moi pour plus de détails.
Comme les fichiers *.cmd peuvent être appelés sans l’extension .cmd , cela permet une expérience multi-plateforme transparente: sous Windows et Unix, vous pouvez appeler une interface de ligne de commande installée par npm par son nom d’origine sans extension.

Les scripts devant être exécutés par un interpréteur ont normalement une ligne shebang en haut pour indiquer au système d’exploitation comment les exécuter.

Si vous avez un script nommé foo dont la première ligne est #!/bin/sh , le système lira cette première ligne et exécutera l’équivalent de /bin/sh foo . De ce fait, la plupart des interpréteurs sont configurés pour accepter le nom d’un fichier script en tant qu’argument de ligne de commande.

Le nom de l’interprète suivant le #! doit être un chemin complet; le système d’exploitation ne recherchera pas votre $PATH pour trouver l’interpréteur.

Si vous avez un script à exécuter par node , le moyen évident d’écrire la première ligne est:

 #!/usr/bin/node 

mais cela ne fonctionne pas si la commande node n’est pas installée dans /usr/bin .

Une solution courante consiste à utiliser la commande env (qui n’était pas vraiment conçue à cet effet):

 #!/usr/bin/env node 

Si votre script s’appelle foo , le système d’exploitation fera l’équivalent de

 /usr/bin/env node foo 

La commande env exécute une autre commande dont le nom est donné sur sa ligne de commande, en transmettant les arguments suivants à cette commande. La raison pour laquelle il est utilisé ici est que env recherche $PATH pour la commande. Donc si node est installé dans /usr/local/bin/node et que vous avez /usr/local/bin dans votre $PATH , la commande env invoquera /usr/local/bin/node foo .

L’objective principal de la commande env est d’exécuter une autre commande avec un environnement modifié, en ajoutant ou en supprimant des variables d’environnement spécifiées avant d’exécuter la commande. Mais sans arguments supplémentaires, il exécute simplement la commande avec un environnement inchangé, ce qui est tout ce dont vous avez besoin dans ce cas.

Cette approche présente certains inconvénients. La plupart des systèmes modernes de type Unix ont /usr/bin/env , mais j’ai travaillé sur des systèmes plus anciens où la commande env était installée dans un répertoire différent. Il peut y avoir des limitations sur les arguments supplémentaires que vous pouvez utiliser en utilisant ce mécanisme. Si l’utilisateur ne possède pas le répertoire contenant la commande node dans $PATH , ou s’il possède une commande différente appelée node , il peut invoquer la mauvaise commande ou ne pas fonctionner du tout.

Les autres approches sont les suivantes:

  • Utilisez un #! ligne qui spécifie le chemin d’access complet à la commande de node elle-même, mettant à jour le script selon les besoins pour différents systèmes; ou
  • Appelez la commande node avec votre script en tant qu’argument.

Voir aussi cette question (et ma réponse ) pour plus de détails sur le tour #!/usr/bin/env .

Incidemment, sur mon système (Linux Mint 17.2), il est installé sous /usr/bin/nodejs . Selon mes notes, il est passé de /usr/bin/node à /usr/bin/nodejs entre Ubuntu 12.04 et 12.10. L’astuce #!/usr/bin/env ne vous aidera pas (sauf si vous configurez un lien symbolique ou quelque chose de similaire).

Réponse courte: C’est le chemin de l’interprète.

EDIT (Réponse longue): La raison pour laquelle il n’y a pas de barre oblique avant “node” est que vous ne pouvez pas toujours garantir la fiabilité de #! / Bin /. Le bit “/ env” rend le programme plus multi-plateforme en exécutant le script dans un environnement modifié et en étant capable de trouver le programme d’interprétation de manière plus fiable.

Vous n’en avez pas forcément besoin, mais il est bon d’utiliser pour assurer la portabilité (et le professionnalisme)