Widziałem tę linię #!/usr/bin/env node
na początku niektórych przykładów w programie nodejs
i przeszukałem go w Google, nie znajdując żadnego tematu, który mógłby odpowiedzieć na przyczynę tej linii.
Charakter słów sprawia, że wyszukiwanie nie jest takie łatwe.
Czytałem trochę javascript
i nodejs
książek niedawno i nie pamiętam widząc go w żadnym z nich.
Jeśli potrzebujesz przykładu, możesz zobaczyć RabbitMQ
oficjalny samouczek , mają go w prawie wszystkich swoich przykładach, oto jeden z nich:
#!/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);
});
Czy ktoś mógłby mi wyjaśnić, jakie jest znaczenie tego wiersza?
Jaka jest różnica, jeśli wstawię lub usunę tę linię? W jakich przypadkach go potrzebuję?
node
npm
zainstalować skrypt źródłowy Node.js jako (potencjalnie dostępny globalnie) CLI , musisz użyć linii shebang - anpm
nawet sprawisz, że będzie działać w systemie Windows; zobacz moją ponownie zaktualizowaną odpowiedź.Odpowiedzi:
#!/usr/bin/env node
to przykład linii shebang : pierwsza linia w wykonywalnym pliku tekstowym na platformach uniksopodobnych, która informuje system, do jakiego interpretera ma przekazać ten plik do wykonania , za pośrednictwem wiersza poleceń następującego po magicznym#!
przedrostku (nazywanym shebang ) .Uwaga: System Windows nie nie obsługują shebang linii , więc są one skutecznie ignorowane tam; w systemie Windows tylko rozszerzenie nazwy pliku danego pliku określa, jaki plik wykonywalny go zinterpretuje. Jednak nadal potrzebujesz ich w kontekście
npm
. [1]Poniższe ogólne omówienie linii shebang jest ograniczone do platform typu Unix:
W poniższej dyskusji zakładam, że plik zawierający kod źródłowy do wykonania przez Node.js ma po prostu nazwę
file
.Ty potrzebujesz tej linii , jeśli chcesz, aby wywołać plik źródłowy node.js bezpośrednio , jako plik wykonywalny w sobie - to zakłada się, że plik został oznaczony jako wykonywalny z polecenia, takie jak
chmod +x ./file
, co następnie pozwala wywołać plik na przykład,./file
lub, jeśli znajduje się w jednym z katalogów wymienionych w$PATH
zmiennej, po prostu jakofile
.npm
podstawie wartości"bin"
klucza wpackage.json
pliku pakietu ; zobacz również tę odpowiedź, aby dowiedzieć się, jak to działa z pakietami zainstalowanymi globalnie . Przypis [1] pokazuje, jak jest to obsługiwane w systemie Windows.Państwo nie trzeba tę linię, aby wywołać plik bezpośrednio poprzez
node
tłumacza, na przykład,node ./file
Opcjonalne informacje dodatkowe :
#!/usr/bin/env <executableName>
jest sposobem przenośnego określenia interpretera: w skrócie mówi: wykonaj,<executableName>
gdziekolwiek (najpierw) znajdziesz go wśród katalogów wymienionych w$PATH
zmiennej (i niejawnie przekaż mu ścieżkę do dostępnego pliku).Wynika to z faktu, że dany interpreter może być zainstalowany w różnych lokalizacjach na różnych platformach, co z pewnością ma miejsce w przypadku
node
pliku binarnego Node.js.Z drugiej strony
env
można polegać na tym, że lokalizacja samego narzędzia znajduje się w tej samej lokalizacji na różnych platformach, a mianowicie/usr/bin/env
- a określenie pełnej ścieżki do pliku wykonywalnego jest wymagane w wierszu shebang.Zwróć uwagę, że narzędzie POSIX
env
jest tu ponownie wykorzystywane do lokalizowania według nazwy pliku i wykonywania pliku wykonywalnego w$PATH
.Prawdziwym celem
env
jest zarządzanie środowiskiem dla polecenia - zobaczenv
specyfikację POSIX i pomocną odpowiedź Keitha Thompsona .Warto również zauważyć, że Node.js robi wyjątek składniowy dla linii shebang, biorąc pod uwagę, że nie są one prawidłowym kodem JavaScript (
#
nie jest znakiem komentarza w JavaScript, w przeciwieństwie do powłok podobnych do POSIX i innych interpreterów).[1] W celu zachowania spójności między platformami,
npm
tworzy pliki opakowujące*.cmd
(pliki wsadowe) w systemie Windows podczas instalowania plików wykonywalnych określonych wpackage.json
pliku pakietu (za pośrednictwem"bin"
właściwości). Zasadniczo te pliki wsadowe opakowania naśladują funkcjonalność uniksowego shebang: wywołują plik docelowy jawnie za pomocą pliku wykonywalnego określonego w wierszu shebang - w związku z tym skrypty muszą zawierać wiersz shebang, nawet jeśli zamierzasz je uruchamiać tylko w systemie Windows - zobacz tę odpowiedź o szczegóły.Ponieważ
*.cmd
pliki można wywoływać bez rozszerzenia.cmd
rozszerzenie, zapewnia to bezproblemowe działanie na wielu platformach: zarówno w systemie Windows, jak i Unix można skutecznie wywołaćnpm
zainstalowany interfejs CLI za pomocą jego oryginalnej nazwy bez rozszerzeń.źródło
.cmd
i.py
określ, jaki program będzie używany do wykonywania takich plików. W systemie Unix funkcję tę pełni linia shebang. Abynpm
działać na wszystkich obsługiwanych platformach, potrzebujesz linii shebang nawet w systemie Windows.Skrypty, które mają być wykonane przez tłumacza, zwykle mają linię szarpnięcia u góry która informuje system operacyjny, jak je wykonać.
Jeśli masz skrypt o nazwie,
foo
którego pierwsza linia to#!/bin/sh
, system odczyta tę pierwszą linię i wykona odpowiednik/bin/sh foo
. Z tego powodu większość interpreterów jest skonfigurowana tak, aby akceptować nazwę pliku skryptu jako argument wiersza poleceń.Nazwa tłumacza występująca po
#!
musi być pełną ścieżką; system operacyjny nie będzie szukał twojego$PATH
tłumacza.Jeśli masz skrypt do wykonania
node
, oczywistym sposobem napisania pierwszej linii jest:ale to nie działa, jeśli
node
polecenie nie jest zainstalowane w/usr/bin
.Typowym obejściem jest użycie
env
polecenia (które tak naprawdę nie było przeznaczone do tego celu):Jeśli Twój skrypt zostanie wywołany
foo
, system operacyjny wykona odpowiednikenv
Polecenie wykonuje inną komendę, którego nazwa podana jest w linii poleceń, przechodząc żadnych następujące argumenty do tego polecenia. Powodem jest to, żeenv
wyszuka$PATH
polecenie. Więc jeślinode
jest zainstalowany/usr/local/bin/node
i masz/usr/local/bin
w swoim$PATH
,env
polecenie zostanie wywołane/usr/local/bin/node foo
.Głównym celem
env
polecenia jest wykonanie innego polecenia w zmodyfikowanym środowisku, dodanie lub usunięcie określonych zmiennych środowiskowych przed uruchomieniem polecenia. Ale bez dodatkowych argumentów, po prostu wykonuje polecenie w niezmienionym środowisku, co jest wszystkim, czego potrzebujesz w tym przypadku.Takie podejście ma pewne wady. Większość nowoczesnych systemów typu Unix ma
/usr/bin/env
, ale pracowałem na starszych systemach, w którychenv
polecenie zostało zainstalowane w innym katalogu. Mogą istnieć ograniczenia dotyczące dodatkowych argumentów, które można przekazać za pomocą tego mechanizmu. Jeśli użytkownik nie ma katalogu zawierającegonode
polecenie$PATH
lub ma inną komendę o nazwienode
, może wywołać niewłaściwe polecenie lub w ogóle nie działać.Inne podejścia to:
#!
wiersza określającego pełną ścieżkę do samegonode
polecenia, aktualizując skrypt zgodnie z potrzebami dla różnych systemów; lubnode
polecenie ze swoim skryptem jako argumentem.Zobacz także to pytanie (i moją odpowiedź ), aby uzyskać więcej informacji na temat
#!/usr/bin/env
sztuczce.Nawiasem mówiąc, w moim systemie (Linux Mint 17.2) jest zainstalowany jako
/usr/bin/nodejs
. Według moich notatek zmieniło się z/usr/bin/node
na/usr/bin/nodejs
między Ubuntu 12.04 a 12.10. Ta#!/usr/bin/env
sztuczka nie pomoże w tym (chyba że skonfigurujesz łącze symboliczne lub coś podobnego).AKTUALIZACJA: komentarz mtraceur mówi (przeformatowano):
Ostatnio nie korzystałem z NodeJS. Mam nadzieję, że problem
nodejs
znode
wersją został rozwiązany w latach, które minęły, odkąd po raz pierwszy opublikowałem tę odpowiedź. W systemie Ubuntu 18.04nodejs
pakiet instaluje się/usr/bin/nodejs
jako łącze symboliczne do/usr/bin/node
. W niektórych wcześniejszych systemach operacyjnych (Ubuntu lub Linux Mint, nie jestem pewien który) istniałnodejs-legacy
pakiet, który był dostarczanynode
jako dowiązanie symboliczne donodejs
. Nie ma gwarancji, że wszystkie szczegóły są prawidłowe.źródło
nodejs
vsnode
polega na uruchomieniu pliku z następującymi sześcioma wierszami: 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)*/
. To najpierw spróbuje,nodejs
a następnie spróbujenode
i wydrukuje komunikaty o błędach tylko wtedy, gdy oba z nich nie zostaną znalezione. Wyjaśnienie jest poza zakresem tych komentarzy, zostawiam je tutaj na wypadek, gdyby pomogło komukolwiek poradzić sobie z problemem, ponieważ ta odpowiedź przyniosła problem.-
na#!
linii?-
W#!/bin/sh -
to tylko przyzwyczajenie sprawia, że na pewno się zachowuje się powłoki w samym bardzo wąski i mało prawdopodobnym zestaw okoliczności, że nazwa skryptu lub względna ścieżka że powłoka zaczyna się widzi-
. (Ponadto, tak, wygląda na to, że każda dystrybucja głównego nurtu powróciła donode
nazwy głównej. Nie szukałem w komentarzu, ale z tego, co wiem, używam tylko drzewa genealogicznego dystrybucji Debiananodejs
i wygląda na to, że tak jak wszyscy wrócili do wspierania,node
gdy zrobił to Debian.)-x
i-v
”, ale ponieważ wczesne polubienia Bourne'a analizowały tylko pierwszy argument jako możliwe opcje, a ponieważ powłoka zaczyna się z wyłączonymi opcjami , powodowanie, że powłoka nie próbowała analizować nazwy skryptu od czasu wydania oryginału, było nadużyciem, ponieważ zachowanie jest utrzymywane we współczesnych polubieniach Bourne'a ze względu na kompatybilność. Jeśli dobrze pamiętam całą moją historię Bourne'a i ciekawostki dotyczące przenośności.Krótka odpowiedź: To droga do tłumacza.
EDYCJA (długa odpowiedź): Przyczyną braku ukośnika przed „węzłem” jest to, że nie zawsze można zagwarantować niezawodność #! / Bin /. Bit „/ env” sprawia, że program jest bardziej wieloplatformowy, uruchamiając skrypt w zmodyfikowanym środowisku i bardziej niezawodnie będąc w stanie znaleźć program interpretujący.
Niekoniecznie jest to potrzebne, ale dobrze jest używać, aby zapewnić przenośność (i profesjonalizm)
źródło
/usr/bin/env
Nieco nie zmienia środowisko. Jest to po prostu polecenie w (głównie) znanej lokalizacji, które wywołuje inne polecenie podane jako argument i wyszukuje$PATH
je. Chodzi o to, że#!
linia wymaga pełnej ścieżki do wywoływanego polecenia i niekoniecznie wiesz, gdzienode
jest zainstalowane.