Що саме робить "/ usr / bin / env node" на початку файлів вузлів?


109

Я бачив цей рядок #!/usr/bin/env nodeна початку деяких прикладів уnodejs і я гуглив, не знайшовши жодної теми, яка могла б відповісти на причину цього рядка.

Природа слів робить пошук не таким простим.

Я прочитав би деякі javascriptіnodejs книги в останній час, і я не пам'ятаю , що бачив його в будь-якому з них.

Якщо ви хочете прикладу, ви можете побачити RabbitMQофіційний підручник , вони є майже у всіх їх прикладах, ось один із них:

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

Чи міг би хтось пояснити мені, в чому сенс цього рядка?

Яка різниця, якщо я поставив або вилучив цей рядок? У яких випадках мені це потрібно?


3
він в основному приймає середовище виклику оболонки і наповнює це середовище в будь-який додаток, що вказано. в цьому випадку,node
Марк Б

Насправді ні, я не приїжджаю з Windows, але дякую за оновлення вашої відповіді. Я просто чекаю, чи не хтось ще вподобає свою думку з різною думкою. Є лише одне, що, я думаю, ви не згадали у своїй відповіді, я просто знаходжу це пару годин тому. Те, що вони згадують тут, здається важливим, але для мене це ще недостатньо зрозуміло. stackoverflow.com/questions/14517535/… (ви можете оновити, якщо хочете, я дійсно оціню це, але не відчуваю це як зобов’язання. Ваша відповідь зараз досить хороша).
Гепсер

@Gepser: Зрозумів. Недолік цього: якщо ви хочете npmвстановити вихідний скрипт Node.js як (потенційно доступний у всьому світі) CLI , ви повинні використовувати рядок shebang - і npmнавіть змусить це працювати в Windows; дивіться мою ще раз оновлену відповідь.
mklement0

"Характер слів робить пошук не таким простим" - ви можете спробувати duckduckgo.com для цього конкретного випадку пошуку
Рікардо

Можливий повторник Чому люди записують #! / Usr / bin / env pybhon shebang в перший рядок сценарію Python? . Те саме питання, різний перекладач.
jww

Відповіді:


146

#!/usr/bin/env nodeє екземпляром рядка shebang : самий перший рядок у виконаному простому текстовому файлі на платформах, подібних Unix, який повідомляє системі, якому інтерпретатору передавати цей файл для виконання , через командний рядок, що слідує за магічним #!префіксом (називається shebang ) .

Примітка: Windows , ніяк НЕ підтримує притон лінії , тому вони ефективно ігноруються там; в 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 та корисну відповідь Кіта Томпсона .


Варто також зазначити, що Node.js робить синтаксичний виняток для рядків shebang, враховуючи, що вони не є дійсним кодом JavaScript ( #не є коментованим символом у JavaScript, на відміну від оболонок, схожих на POSIX та інших інтерпретаторів).


[1] В інтересах узгодженості між платформами npmстворює обгорткові *.cmd файли (пакетні файли) у Windows під час встановлення виконуваних файлів, визначених у package.jsonфайлі пакету (через "bin"властивість). По суті, ці пакетні файли обгортки імітують функціональність Unix shebang: вони чітко викликають цільовий файл із виконуваним файлом, визначеним у рядку shebang - таким чином, ваші сценарії повинні містити рядок shebang, навіть якщо ви коли-небудь збираєтеся запускати їх у Windows - дивіться цю відповідь мій для деталей.
Оскільки *.cmdфайли можна викликати без.cmdрозширення, це спричиняє бездоганний досвід роботи на платформі: і в Windows, і в Unix ви можете ефективно викликати npmінстальований CLI за його оригінальним іменем без розширення.


Чи можете ви надати пояснення чи резюме для манекенів, як я?
Ендрю Лам

4
@AndrewLam: У Windows розширення імен файлів, наприклад, .cmdта .pyвизначають, яка програма буде використовуватися для виконання таких файлів. У Unix лінія shebang виконує цю функцію. Щоб npmпрацювати на всіх підтримуваних платформах, вам потрібна лінія shebang навіть у Windows.
mklement0

28

Сценарії, які повинен виконати інтерпретатор, зазвичай мають верхню рядок 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 vs node - запустити файл із наступних шести рядків:

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

Спершу це спробує, nodejsа потім спробує nodeта надрукує повідомлення про помилку, лише якщо їх обох не знайдено. Пояснення не входить в рамки цих коментарів, я просто залишаю його на випадок, якщо це допоможе комусь впоратися з проблемою, оскільки ця відповідь підняла проблему.

Останнім часом я не використовував NodeJS. Я сподіваюся, що nodejsпроти nodeпитання вирішено в роки, коли я вперше опублікував цю відповідь. У Ubuntu 18.04 nodejsпакет встановлюється /usr/bin/nodejsяк символьне посилання на /usr/bin/node. У деяких попередніх ОС (Ubuntu або Linux Mint, я не впевнений, який), був nodejs-legacyпакет, який забезпечувався nodeяк посилання на nodejs. Ніякої гарантії, що я маю всі деталі.


Дуже ґрунтовна відповідь, що дає чому справи.
Сурай Джайн

1
Вирішення проблеми nodejsvs node- це запустити файл із наступних шести рядків: 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>&26) */. Спершу це спробує, nodejsа потім спробує nodeта надрукує повідомлення про помилку, лише якщо їх обох не знайдено. Пояснення не входить в рамки цих коментарів, я просто залишаю його на випадок, якщо це допоможе комусь впоратися з проблемою, оскільки ця відповідь підняла проблему.
mtraceur

@mtraceur: Я включив ваш коментар у свою відповідь. Чому -на #!лінії?
Кіт Томпсон,

-У #!/bin/sh -це просто звичка , яка гарантує , що веде себе оболонку прямо в дуже вузькому і малоймовірному збігу обставин , що ім'я сценарію або відносний шлях , що оболонка бачить починається з -. (Так, так, схоже, що кожен основний дистрибутив конвертувався назад в nodeякості основного імені. Я не пішов копатися, щоб перевірити, роблячи коментар, але, наскільки я знаю, використовується лише сімейне дерево дистрибутива Debian nodejs, і це виглядає як і всі вони повернулися до того, щоб підтримати nodeколись Debian.)
mtraceur

Технічно один тире як перший аргумент не означав "закінчення параметрів" - він спочатку означав "вимкнути -xі -v", але оскільки ранній Борн-лайк лише розбирав перший аргумент як можливі варіанти, і оскільки оболонка починається з цих параметрів, вимкнено , це може зловмисно змусити оболонку не намагатися проаналізувати ім'я сценарію з оригіналу, і, таким чином, залишається таким чином зловживаним, оскільки поведінка підтримується в сучасних подібних Bourne з міркувань сумісності. Якщо я пам’ятаю всю свою історію Борна та дрібниці портативності.
mtraceur

0

Коротка відповідь: Це шлях до перекладача.

EDIT (довга відповідь): Причина відсутності косої риски перед "вузлом" полягає в тому, що ви не завжди можете гарантувати надійність #! / Bin /. Біт "/ env" робить програму більш кросплатформою, запускаючи скрипт у модифікованому середовищі та надійніше знаходити програму інтерпретатора.

Вам це не обов'язково потрібно, але це добре використовувати для забезпечення портативності (і професіоналізму)


1
/usr/bin/envБіт не змінює навколишнє середовище. Це просто команда в (здебільшого) відомому місці, яка викликає іншу команду, задану як аргумент, і шукає $PATHїї знайти. Справа в тому, що #!рядок вимагає повного шляху до виклику команди, і ви не обов'язково знаєте, де nodeвстановлено.
Кіт Томпсон

На це я йшов, дякую за уточнення!
Квантовий
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.