Подтвердить что ты не робот

Что именно делает "/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);
});

Может ли кто-нибудь объяснить мне, в чем смысл этой строки?

В чем разница, если я поместил или удалю эту строку? В каких случаях он мне нужен?

4b9b3361

Ответ 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 в измененной среде и более надежно найдя программу-переводчик.

Вам это не обязательно, но полезно использовать для обеспечения переносимости (и профессионализма)