web-dev-qa-db-fra.com

Que fait exactement "/ usr / bin / env node" 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 cherché sur Google sans trouver de sujet pouvant répondre à la raison de cette ligne.

La nature des mots rend la recherche difficile.

Je lisais récemment javascript et nodejs et je ne me souvenais pas de l'avoir vu dans aucun d'entre eux.

Si vous voulez un exemple, vous pouvez voir le RabbitMQ officiel tutoriel , 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?

78
Gepser

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

Remarque: Windows fait pas prend en charge les lignes Shebang , elles sont donc efficaces. ignoré là; sous Windows, c'est uniquement l'extension du nom de fichier d'un fichier donné qui détermine quel exécutable l'interprétera. Cependant, vous en avez toujours besoin dans le contexte de npm.[1]

La discussion générale suivante sur les lignes Shebang est limitée aux plates-formes de type Unix:

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

  • Vous BESOIN de cette ligne , si vous souhaitez appeler un fichier source Node.js directement, en tant qu'exécutable dans son propre droit - cela suppose que le fichier a été marqué comme exécutable avec une commande telle que chmod +x ./file, qui vous permet ensuite d’appeler le fichier avec, par exemple, ./file, ou, s’il se trouve dans l’un des répertoires énumérés dans le $PATH variable, simplement comme file.

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


Informations de base facultatives :

#!/usr/bin/env <executableName> est un moyen de transférable spécifier un interprète: en un mot, il est écrit: execute <executableName> _ où que vous trouviez (le premier) parmi les répertoires listés dans le $PATH variable (et lui transmettra implicitement le chemin du fichier à traiter).

Cela explique le fait qu’un interprète donné peut être installé à différents endroits d’une plate-forme à l’autre, ce qui est certainement le cas de node, le binaire Node.js.

En revanche, l'emplacement de l'utilitaire env lui-même peut être considéré comme situé dans l'emplacement identique sur plusieurs plates-formes, à savoir /usr/bin/env - et en spécifiant le chemin complet vers un exécutable est obligatoire dans une ligne Shebang.

Notez que l'utilitaire POSIX env est en train d'être réutilisé ici pour localiser par nom de fichier et exécuter un exécutable dans le $PATH.
Le but réel de env est de gérer l'environnement pour une commande - voir la spécification POSIX de env et réponse utile de Keith Thompson .


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


[1] Dans l'intérêt de la cohérence entre plates-formes, npm crée wrapper*.cmd fichiers (fichiers de commandes) sous Windows lors de l’installation des exécutables spécifiés dans le fichier package.json fichier (via le fichier "bin" propriété). Essentiellement, ces fichiers de traitement par lots mimiques Fonctionnalités Unix Shebang: ils invoquent explicitement le fichier cible avec l’exécutable spécifié dans la ligne Shebang - ainsi, vos scripts doivent inclure une ligne Shebang même si vous avez toujours l'intention de les exécuter sous Windows - voir cette réponse à moi pour plus de détails.
Puisque *.cmd les fichiers peuvent être appelés sans le .cmd extension, cela permet une expérience multi-plateforme transparente: sous Windows et Unix, vous pouvez effectivement appeler une CLI installée par npm- par son nom d'origine, sans extension.

110
mklement0

Les scripts qui doivent être exécutés par un interprète ont normalement un 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ètes sont configurés pour accepter le nom d'un fichier de 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 cherchera pas votre $PATH pour trouver l'interprète.

Si vous avez un script à exécuter par node, la manière évidente d'écrire la première ligne est la suivante:

#!/usr/bin/node

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

Une solution de contournement courante consiste à utiliser la commande env (qui n'était pas vraiment à cette fin):

#!/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 cherchera $PATH pour la commande. Donc, si node est installé dans /usr/local/bin/node, et tu as /usr/local/bin dans votre $PATH, la commande env invoquera /usr/local/bin/node foo.

Le but 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 quelques inconvénients. La plupart des systèmes de type Unix modernes ont /usr/bin/env, mais j’ai travaillé sur des systèmes plus anciens où la commande env était installée dans un autre répertoire. Il peut y avoir des limites aux arguments supplémentaires que vous pouvez transmettre à l'aide de ce mécanisme. Si l'utilisateur ne possède pas le répertoire contenant la commande node dans $PATH, ou a une commande différente appelée node, elle pourrait alors invoquer la mauvaise commande ou ne pas fonctionner du tout.

Les autres approches sont:

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

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

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

UPDATE: Un commentaire de mtraceur dit (reformaté):

Une solution de contournement pour le problème nodejs vs node consiste à démarrer le fichier avec les six lignes suivantes:

#!/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
*/

Ceci va d’abord essayer nodejs, puis node, et n’afficher que les messages d’erreur si les deux ne sont pas trouvés. Une explication est hors de portée de ces commentaires, je la laisse simplement ici au cas où cela aiderait quelqu'un à résoudre le problème, puisque cette réponse a soulevé le problème.

Je n'ai pas utilisé NodeJS ces derniers temps. Mon espoir est que le problème nodejs vs node a été résolu dans les années écoulées depuis que j'ai posté cette réponse pour la première fois. Sur Ubuntu 18.04, le paquet nodejs installe /usr/bin/nodejs comme lien symbolique vers /usr/bin/node. Sur certains systèmes d'exploitation antérieurs (Ubuntu ou Linux Mint, je ne sais pas lequel), il y avait un nodejs-legacy paquet qui a fourni node sous forme de lien symbolique vers nodejs. Aucune garantie que j'ai tous les détails du droit.

25
Keith Thompson

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 "noeud" est parce 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 permettant de trouver le programme interprète de manière plus fiable.

Vous n'en avez pas nécessairement besoin, mais il est bon de l'utiliser pour assurer la portabilité (et le professionnalisme)

0
Quantum