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 qui pourrait répondre à la raison de cette ligne.
La nature des mots ne facilite pas la recherche.
J'en avais lu quelques javascript
- uns et des nodejs
livres récemment et je ne me souvenais pas l'avoir vu dans aucun d'entre eux.
Si vous voulez un exemple, vous pouvez voir le tutorielRabbitMQ
officiel , 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?
node
npm
installer un script source Node.js en tant que CLI (potentiellement disponible dans le monde entier) , vous devez utiliser une ligne shebang - etnpm
cela fonctionnera même sous Windows; voir ma réponse mise à jour une fois de plus.Réponses:
#!/usr/bin/env node
est une instance d'une ligne shebang : la toute première ligne d'un fichier exécutable en texte brut sur des plates-formes de type Unix qui indique au système à quel interpréteur passer ce fichier pour exécution , via la ligne de commande suivant le#!
préfixe magique (appelé shebang ) .Remarque: Windows ne prend pas en charge les lignes shebang , elles y sont donc effectivement ignorées ; sous Windows, c'est uniquement l' extension de 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 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 un fichier source Node.js directement , 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 vous permet ensuite d'appeler le fichier avec, par exemple,./file
ou, s'il se trouve dans l'un des répertoires répertoriés dans la$PATH
variable, simplement sous la formefile
.npm
fonction de la valeur de la"bin"
clé dans lepackage.json
fichier d' un package ; Consultez également cette réponse pour savoir comment cela fonctionne avec les packages installés globalement . La note de bas de page [1] montre comment cela est géré sous Windows.Vous n'avez PAS besoin de cette ligne pour appeler un fichier explicitement via l'
node
interpréteur, par exemple,node ./file
Informations générales facultatives :
#!/usr/bin/env <executableName>
est un moyen de spécifier un interpréteur de manière portable : en un mot, il dit: exécutez<executableName>
partout où vous le trouvez (en premier) parmi les répertoires listés dans la$PATH
variable (et passez-lui implicitement le chemin du fichier en question).Cela explique le fait qu'un interpréteur donné peut être installé à différents endroits sur les plates-formes, ce qui est certainement le cas avec
node
le binaire Node.js.En revanche, l'emplacement de l'
env
utilitaire lui-même peut être considéré comme étant au même emplacement sur toutes les plates-formes, à savoir/usr/bin/env
- et la spécification du chemin complet vers un exécutable est requise dans une ligne shebang.Notez que l'utilitaire POSIX
env
est en cours de réutilisation ici pour localiser par nom de fichier et exécuter un exécutable dans le$PATH
.Le véritable objectif de
env
est de gérer l'environnement d'une commande - voirenv
les spécifications POSIX de et la réponse utile de Keith Thompson .Il est également intéressant de noter que Node.js crée une exception de syntaxe pour les lignes shebang, étant donné qu'il ne s'agit pas de code JavaScript valide (ce
#
n'est pas un caractère de commentaire en JavaScript, contrairement aux shells de type POSIX et autres interpréteurs).[1] Dans l'intérêt de la cohérence multiplateforme,
npm
crée des fichiers wrapper*.cmd
(fichiers batch) sous Windows lors de l'installation des exécutables spécifiés dans lepackage.json
fichier d' un package (via la"bin"
propriété). Essentiellement, ces fichiers batch wrapper imitent la fonctionnalité Unix shebang: ils invoquent le fichier cible explicitement avec l'exécutable spécifié dans la ligne shebang - ainsi, vos scripts doivent inclure une ligne shebang même si vous avez l'intention de les exécuter uniquement sous Windows - voir cette réponse du mien pour plus de détails.Étant donné que les
*.cmd
fichiers peuvent être appelés sans le.cmd
, cela permet une expérience multiplateforme transparente: sous Windows et Unix, vous pouvez effectivement appeler unenpm
CLI installée par son nom d'origine, sans extension.la source
.cmd
et.py
déterminent quel programme sera utilisé pour exécuter ces fichiers. Sous Unix, la ligne shebang remplit cette fonction. Pournpm
fonctionner sur toutes les plates-formes prises en charge, vous avez besoin de la ligne shebang, même sous Windows.Les scripts qui doivent ê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
. Pour cette raison, la plupart des interpréteurs sont configurés pour accepter le nom d'un fichier de script comme argument de ligne de commande.Le nom de l'interpréteur qui suit
#!
doit être un chemin complet; le système d'exploitation ne recherchera pas votre$PATH
pour trouver l'interprète.Si vous avez un script à exécuter
node
, la manière la plus évidente d'écrire la première ligne est:mais cela ne fonctionne pas si la
node
commande n'est pas installée dans/usr/bin
.Une solution de contournement courante consiste à utiliser la
env
commande (qui n'était pas vraiment destinée à cet effet):Si votre script est appelé
foo
, le système d'exploitation fera l'équivalent deLa
env
commande exécute une autre commande dont le nom est donné sur sa ligne de commande, en passant les arguments suivants à cette commande. La raison pour laquelle il est utilisé ici est qu'ilenv
recherchera$PATH
la commande. Donc, sinode
est installé dans/usr/local/bin/node
, et que vous avez/usr/local/bin
dans votre$PATH
, laenv
commande invoquera/usr/local/bin/node foo
.L'objectif principal de la
env
commande 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 dont vous avez besoin dans ce cas.Cette approche présente certains inconvénients. La plupart des systèmes modernes de type Unix l'ont fait
/usr/bin/env
, mais j'ai travaillé sur des systèmes plus anciens où laenv
commande était installée dans un répertoire différent. Il peut y avoir des limitations sur les arguments supplémentaires que vous pouvez transmettre à l'aide de ce mécanisme. Si l'utilisateur n'a pas le répertoire contenant lanode
commande dans$PATH
, ou si une commande différente est appeléenode
, alors il pourrait appeler la mauvaise commande ou ne pas fonctionner du tout.D'autres approches sont:
#!
ligne qui spécifie le chemin complet de lanode
commande elle-même, en mettant à jour le script selon les besoins pour différents systèmes; ounode
commande avec votre script comme argument.Voir aussi cette question (et ma réponse ) pour plus de discussion sur l'
#!/usr/bin/env
astuce.Incidemment, sur mon système (Linux Mint 17.2), il est installé en tant que
/usr/bin/nodejs
. Selon mes notes, il est passé de/usr/bin/node
à/usr/bin/nodejs
entre Ubuntu 12.04 et 12.10. L'#!/usr/bin/env
astuce n'aidera pas avec cela (à moins que vous ne configuriez un lien symbolique ou quelque chose de similaire).MISE À JOUR: Un commentaire de mtraceur dit (reformaté):
Je n'ai pas utilisé NodeJS récemment. J'espère que le problème du
nodejs
vsnode
a été résolu dans les années qui ont suivi la première publication de cette réponse. Sur Ubuntu 18.04, lenodejs
package s'installe en/usr/bin/nodejs
tant que 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 unnodejs-legacy
package qui était fourni ennode
tant que lien symbolique versnodejs
. Aucune garantie que j'ai tous les détails.la source
nodejs
vsnode
consiste à démarrer le fichier avec les six lignes suivantes: 1)#!/bin/sh -
, 2)':' /*-
3)test1=$(nodejs --version 2>&1) && exec nodejs "$0" "$@"
4)test2=$(node --version 2>&1) && exec node "$0" "$@"
, 5)exec printf '%s\n' "$test1" "$test2" 1>&2
6)*/
. Cela essaiera d'abordnodejs
, puis essaieranode
, et n'imprimera les messages d'erreur que si les deux ne sont pas trouvés. Une explication est hors de portée de ces commentaires, je la laisse juste ici au cas où cela aiderait quiconque à résoudre le problème puisque cette réponse a soulevé le problème.-
sur la#!
ligne?-
in#!/bin/sh -
est juste une habitude qui garantit que le shell se comporte correctement dans l'ensemble extrêmement étroit et improbable de circonstances où le nom du script ou le chemin relatif que le shell voit commence par un-
. (De plus, oui, il semble que toutes les distributions grand public étaient redevenuesnode
le nom principal. Je n'ai pas cherché à vérifier en faisant mon commentaire, mais pour autant que je sache, seul l'arbre généalogique de la distribution Debian utilisénodejs
, et il semble comme ils sont tous revenus au supportnode
une fois que Debian l'a fait.)-x
et-v
", mais depuis les premiers Bourne-likes n'ont analysé que le premier argument comme des options possibles, et puisque le shell commence avec ces options désactivées , il était abusif de faire en sorte que le shell n'essaie pas d'analyser le nom du script depuis l'original, et reste ainsi abusable car le comportement est maintenu dans les Bourne-likes modernes pour des raisons de compatibilité. Si je me souviens de toute mon histoire de Bourne et de mes anecdotes sur la portabilité.Réponse courte: c'est le chemin vers 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 multiplateforme en exécutant le script dans un environnement modifié et en étant plus fiable en mesure de trouver le programme d'interprétation.
Vous n'en avez pas forcément besoin, mais il est bon de l'utiliser pour assurer la portabilité (et le professionnalisme)
la source
/usr/bin/env
bit ne modifie pas l'environnement. C'est juste une commande à un emplacement (principalement) connu qui invoque une autre commande donnée en argument et cherche$PATH
à la trouver. Le fait est que la#!
ligne nécessite le chemin complet de la commande appelée, et vous ne savez pas nécessairement oùnode
est installé.