Что именно делает "/usr/bin/env node" в начале файлов node?
Я видел эту строку #!/usr/bin/env node
в начале некоторых примеров в nodejs
, и я искал googled, не найдя ни одной темы, которая могла бы ответить на причину этой строки.
Характер слов делает поиск не таким легким.
Недавно я читал несколько книг javascript
и nodejs
, и я не помню, чтобы их видели в любом из них.
Если вам нужен пример, вы можете увидеть официальное RabbitMQ
tutorial, оно есть у почти всех их примеров, вот один из них
#!/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);
});
Может ли кто-нибудь объяснить мне, в чем смысл этой строки?
В чем разница, если я поместил или удалю эту строку? В каких случаях он мне нужен?
Ответы
Ответ 1
#!/usr/bin/env node
экземпляр строка shebang: самая первая строка в исполняемом текстовом тексте файл на Unix-подобных платформах, который сообщает системе, какой интерпретатор должен передать этот файл для выполнения, через командную строку после префикса magic #!
(называемый shebang).
Примечание. Windows не поддерживает строки shebang, поэтому они фактически игнорируются там; в Windows это только заданное расширение имени файла, которое определяет, какой исполняемый файл интерпретирует его. Однако они все еще нуждаются в них в контексте npm
. [1]
Следующее, общее обсуждение строк shebang ограничено Unix-подобными платформами:
В следующем обсуждении я предполагаю, что файл, содержащий исходный код для выполнения Node.js, просто называется file
.
- НУЖДАЙТЕ эту строку, если вы хотите напрямую ссылаться на исходный файл Node.js, как самостоятельный исполняемый файл - это предполагает, что файл был помечен как исполняемый с помощью команды, такой как
chmod +x ./file
, которая затем позволяет вызывать файл с, например, ./file
, или, если он находится в одном из каталогов, перечисленных в переменной $PATH
, просто как file
.
- В частности, вам нужна строка shebang для создания CLI на основе исходных файлов Node.js как часть пакета npm, с CLI (-ами), которые должны быть установлены
npm
на основе значения "bin"
ключ в пакете package.json
файл; также см. этот ответ о том, как это работает с глобально установленными пакетами. Сноска [1] показывает, как это обрабатывается в Windows.
- НЕ нужна эта строка, чтобы явно вызывать файл через интерпретатор
node
, например node ./file
Дополнительная справочная информация:
#!/usr/bin/env <executableName>
- это способ портативного указания интерпретатора: в двух словах он говорит: выполните <executableName>
везде, где вы (сначала) найдете его среди каталогов, перечисленных в переменной $PATH
(и неявно передайте ему путь в файл под рукой).
Это объясняет тот факт, что данный интерпретатор может быть установлен в разных местах на разных платформах, что определенно имеет место с node
, двоичным файлом Node.js.
Напротив, расположение самой утилиты env
может быть основано на том, что оно находится в одном месте на разных платформах, а именно /usr/bin/env
- и указание полного пути к исполняемому файлу требуется в строке shebang.
Обратите внимание, что утилита POSIX env
перестраивается здесь, чтобы найти по имени файла и выполнить исполняемый файл в $PATH
.
Истинная цель env
- управлять средой для команды - см. env
POSIX spec и Полезный ответ Кейта Томпсона.
Также стоит отметить, что Node.js делает исключение синтаксиса для строк shebang, учитывая, что они не являются действительными JavaScript-кодом (#
не является символом комментария в JavaScript, в отличие от POSIX-подобных оболочек и другие переводчики).
[1] В интересах кросс-платформенной согласованности npm
создает файлы обложки *.cmd
(пакетные файлы) в Windows при установке исполняемых файлов, указанных в пакете package.json
файла (через свойство "bin"
). По сути, эти пакетные файлы обертки имитируют функциональность Unix shebang: они явно ссылаются на целевой файл с исполняемым файлом, указанным в строке shebang. Таким образом, ваши сценарии должны включать строку shebang, даже если вы только когда-либо намеревается запустить их в Windows - см. этот ответ.
Поскольку *.cmd
файлы могут быть вызваны без расширения .cmd
, это обеспечивает беспрепятственную кросс-платформенную работу: как в Windows, так и в Unix вы можете эффективно вызывать CLI npm
с помощью своего исходного, без расширения имени.
Ответ 2
Сценарии, которые должны выполняться интерпретатором, обычно имеют верхнюю строку shebang, чтобы сообщить ОС, как их выполнять.
Если у вас есть скрипт с именем foo
, первой строкой которого является #!/bin/sh
, система прочитает эту первую строку и выполнит эквивалент /bin/sh foo
. Из-за этого большинство интерпретаторов настроены на прием имени файла сценария в качестве аргумента командной строки.
Имя переводчика после #!
должен быть полный путь; ОС не будет искать ваш $PATH
чтобы найти переводчика.
Если у вас есть скрипт, который будет выполняться node
, очевидный способ написать первую строку:
#!/usr/bin/node
но это не работает, если команда node
не установлена в /usr/bin
.
Обычный обходной путь - использовать команду env
(которая на самом деле не предназначалась для этой цели):
#!/usr/bin/env node
Если ваш скрипт называется foo
, ОС сделает эквивалент
/usr/bin/env node foo
Команда env
выполняет другую команду, имя которой указано в командной строке, передавая следующие аргументы этой команде. Причина, по которой он здесь используется, заключается в том, что env
будет искать команду $PATH
. Так что, если node
установлен в /usr/local/bin/node
, а у вас есть /usr/local/bin
в вашем $PATH
, команда env
вызовет /usr/local/bin/node foo
.
Основная цель команды env
- выполнить другую команду с измененной средой, добавив или удалив указанные переменные среды перед выполнением команды. Но без дополнительных аргументов, он просто выполняет команду с неизменной средой, и это все, что вам нужно в этом случае.
У этого подхода есть некоторые недостатки. Большинство современных Unix-подобных систем имеют /usr/bin/env
, но я работал на старых системах, где команда env
была установлена в другой каталог. Могут быть ограничения на дополнительные аргументы, которые вы можете передать с помощью этого механизма. Если у пользователя нет каталога, содержащего команду node
в $PATH
, или есть какая-то другая команда, называемая node
, то он может вызвать неправильную команду или вообще не работать.
Другие подходы:
- Используйте
#!
строка, которая указывает полный путь к самой команде node
, обновляя скрипт по мере необходимости для разных систем; или же - Вызовите команду
node
с вашим скриптом в качестве аргумента.
См. Также этот вопрос (и мой ответ) для более подробного обсуждения уловки #!/usr/bin/env
.
Кстати, в моей системе (Linux Mint 17.2) он установлен как /usr/bin/nodejs
. Согласно моим заметкам, он изменился с /usr/bin/node
на /usr/bin/nodejs
Ubuntu 12.04 и 12.10. Трюк #!/usr/bin/env
не поможет с этим (если вы не установите символическую ссылку или что-то подобное).
ОБНОВЛЕНИЕ: комментарий mtraceur говорит (переформатирован):
Обходной путь для проблемы nodejs против узла - запустить файл со следующими шестью строками:
#!/bin/sh -
':' /*-
test1=$(nodejs --version 2>&1) && exec nodejs "$0" "[email protected]"
test2=$(node --version 2>&1) && exec node "$0" "[email protected]"
exec printf '%s\n' "$test1" "$test2" 1>&2
*/
Сначала он попытается использовать nodejs
а затем попытаться использовать node
и распечатать сообщения об ошибках, только если оба они не найдены. Объяснение выходит за рамки этих комментариев, я просто оставляю его здесь на случай, если оно поможет кому-либо разобраться с проблемой, так как этот ответ поднял проблему.
Я не использовал NodeJS в последнее время. Я надеюсь, что nodejs
против node
была решена за те годы, когда я впервые опубликовал этот ответ. В Ubuntu 18.04 пакет nodejs
устанавливает /usr/bin/nodejs
как символическую ссылку на /usr/bin/node
. На некоторых более ранних nodejs-legacy
ОС (Ubuntu или Linux Mint, я не уверен, какая именно) существовал nodejs-legacy
пакет nodejs-legacy
, предоставляющий node
в качестве символической ссылки на nodejs
. Нет гарантии, что у меня все детали в порядке.
Ответ 3
Короткий ответ:
Это путь к интерпретатору.
EDIT (длинный ответ):
Причина отсутствия косой черты перед "node" заключается в том, что вы не всегда можете гарантировать надежность #!/Bin/. Бит "/env" делает программу более кросс-платформенной, запустив script в измененной среде и более надежно найдя программу-переводчик.
Вам это не обязательно, но полезно использовать для обеспечения переносимости (и профессионализма)