Düğüm dosyalarının başında “/ usr / bin / env düğümü” tam olarak ne yapar?


109

Bu satırı #!/usr/bin/env nodebazı örneklerin başında görmüştüm nodejsve o satırın nedenine cevap verebilecek herhangi bir konu bulmadan googledim.

Kelimelerin doğası, aramayı o kadar da kolaylaştırmıyor.

Son zamanlarda birkaç kitap okudum javascriptve nodejshiçbirinde gördüğümü hatırlamıyordum.

Bir örnek istiyorsanız, RabbitMQresmi öğreticiyi görebilirsiniz, neredeyse tüm örneklerinde var, işte bunlardan biri:

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

Birisi bana bu satırın anlamını açıklayabilir mi?

Bu satırı koyarsam veya kaldırırsam ne fark eder? Hangi durumlarda ihtiyacım var?


3
temelde çağıran kabuğun ortamını alır ve bu ortamı hangi uygulama belirtilmişse içine doldurur. bu durumda,node
Marc B

Aslında hayır, Windows'tan gelmiyorum, ancak cevabınızı güncellediğiniz için teşekkür ederim. Başka birinin farklı bir görüşle gelip gelmediğini görmek için bekliyorum. Cevabınızda bahsetmediğini düşündüğüm tek bir şey var, bunu birkaç saat önce buldum. Burada bahsettikleri şeyler önemli görünüyor ama benim için henüz yeterince açık değil. stackoverflow.com/questions/14517535/… (İsterseniz güncelleme yapabilirsiniz, bunu gerçekten takdir ederim, ancak bunu bir zorunluluk gibi hissetmeyin, cevabınız şu anda yeterince iyi).
Gepser

@Gepser: Anladım. Bunun kısa: İsterseniz npmbir (potansiyel olarak küresel olarak kullanılabilir) gibi node.js kaynak komut dosyası yüklemek için CLI , sen gerekir Bir shebang satırını kullanın - ve npmhatta Windows üzerinde bu işi yapacak; bir kez daha güncellenen cevabımı görün.
mklement0

"Kelimelerin doğası, aramayı o kadar kolay yapmıyor" - bu özel arama kullanım örneği için duckduckgo.com'u denemek isteyebilirsiniz
Ricardo

Yanıtlar:


146

#!/usr/bin/env nodeolan bir örneğidir shebang hattı : üzerinde bir çalıştırılabilir düz metin dosyasında ilk satırı Unix benzeri platformlar yürütülmesi için bu dosyayı geçirmek için ne tercüman sistemini anlatır sihirli aşağıdaki komut satırı üzerinden, #!önek (denilen mesele ) .

Not: , Windows gelmez değil shebang çizgileri desteklemek , bu yüzden etkili bir konum göz ardı orada; Windows'ta, onu hangi yürütülebilir dosyanın yorumlayacağını belirleyen , yalnızca belirli bir dosyanın dosya adı uzantısıdır . Ancak, bağlamında hala onlara ihtiyacınız varnpm . [1]

Aşağıdaki, shebang satırlarının genel tartışması, Unix benzeri platformlarla sınırlıdır:

Aşağıdaki tartışmada, Node.js tarafından yürütülecek kaynak kodunu içeren dosyanın basitçe adlandırıldığını varsayacağım file.

  • Sen bu satırı İHTİYACINIZ Bir node.js kaynak dosyasını çağırmak istiyorsanız, doğrudan kendi başına bir yürütülebilir dosya olarak, - bu dosya gibi bir komut ile yürütülebilir olarak işaretlenmiş varsayar chmod +x ./fileardından dosyayı çağırmak için izin veren Örneğin, ./fileveya $PATHdeğişkende listelenen dizinlerden birinde bulunuyorsa , sadece file.

    • Özellikle, bir paket dosyasındaki anahtarın değerine bağlı olarak yüklenecek CLI (ler) ile bir npm paketinin bir parçası olarak Node.js kaynak dosyalarına dayalı CLI'ler oluşturmak için bir shebang satırına ihtiyacınız vardır ; ayrıca bunun küresel olarak kurulu paketlerle nasıl çalıştığını öğrenmek için bu yanıta bakın . Dipnot [1] bunun Windows'ta nasıl işlendiğini gösterir.npm"bin"package.json
  • Sen gerekmediğini açıkça üzerinden bir dosyayı çağırmak için bu satırı node, örneğin tercümannode ./file


İsteğe bağlı arka plan bilgileri :

#!/usr/bin/env <executableName>bir yorumlayıcıyı taşınabilir bir şekilde belirtmenin bir yoludur : kısaca şunu söyler: <executableName>onu $PATHdeğişkende listelenen dizinler arasında bulduğunuz her yerde (ilk önce) çalıştırın (ve dolaylı olarak eldeki dosyanın yolunu iletin).

Bu, belirli bir yorumlayıcının platformlar arasında farklı konumlara kurulabileceği gerçeğini açıklar, bu kesinlikle nodeNode.js ikili dosyasında olduğu gibi.

Buna karşılık, envyardımcı programın konumunun, platformlar arasında aynı konumda olduğuna güvenilebilir , yani /usr/bin/env- ve bir shebang satırında bir yürütülebilir dosyanın tam yolunu belirtmek gerekir .

POSIX yarar ki Not envolan başka bir amaca uygun dosya göre ve bir yürütülebilir yürütmek için $PATH.
Bunun gerçek amacı, envbir komut için ortamı yönetmektir - envPOSIX spesifikasyonuna ve Keith Thompson'ın yardımcı cevabına bakın .


Ayrıca, Node.js'nin, geçerli JavaScript kodu olmadıkları göz önüne alındığında, shebang satırları için bir sözdizimi istisnası yaptığını da belirtmek gerekir ( #POSIX benzeri kabuklar ve diğer yorumlayıcıların aksine, JavaScript'te bir yorum karakteri değildir).


[1] Platformlar arası tutarlılık açısından, bir paketin dosyasında ( özellik aracılığıyla ) belirtilen yürütülebilir dosyaları yüklerken Windows'ta sarmalayıcı dosyaları (toplu iş dosyaları) npmoluşturur *.cmd . Esasen, bu sarmalayıcı toplu iş dosyaları Unix shebang işlevini taklit eder: hedef dosyayı, shebang satırında belirtilen yürütülebilir dosya ile açıkça çağırırlar - bu nedenle, komut dosyalarınız yalnızca Windows'ta çalıştırmayı planlasanız bile bir shebang satırı içermelidir - bu yanıta bakın detaylar için benim. Yana dosyalar olmadan çağrılabilirpackage.json"bin"
*.cmd.cmduzantısı, bu sorunsuz bir çapraz platform deneyimi sağlar: hem Windows hem de Unix'te-kurulu bir npmCLI'yi orijinal, uzantısız adıyla etkin bir şekilde çağırabilirsiniz .


Benim gibi aptallar için bir açıklama veya özet verebilir misiniz?
Andrew Lam

4
@AndrewLam: Windows'ta, gibi dosya adı uzantıları .cmdve .pybu tür dosyaları çalıştırmak için hangi programın kullanılacağını belirler. Unix'te, shebang satırı bu işlevi yerine getirir. Yapmak için npmtüm desteklenen platformlarında çalışmalarını, hatta Windows üzerinde shebang hat istiyorum.
mklement0

28

Bir yorumlayıcı tarafından çalıştırılacak komut dosyalarının normalde üstte işletim sistemine bunları nasıl çalıştıracağını söyleyen bir shebang satırı vardır.

fooİlk satırı olan bir betik adınız varsa #!/bin/sh, sistem o ilk satırı okuyacak ve eşdeğerini çalıştıracaktır /bin/sh foo. Bu nedenle, çoğu yorumlayıcı bir komut dosyası dosyasının adını komut satırı argümanı olarak kabul edecek şekilde ayarlanmıştır.

Aşağıdaki yorumlayıcı adı #!tam bir yol olmalıdır; OS $PATH, tercümanı bulmak için sizin arama yapmaz .

Çalıştırılacak bir komut dosyanız varsa node, ilk satırı yazmanın en açık yolu şudur:

#!/usr/bin/node

ancak nodekomut yüklü değilse bu çalışmaz /usr/bin.

Yaygın bir çözüm, envkomutu kullanmaktır ( aslında bu amaç için tasarlanmamıştır):

#!/usr/bin/env node

Komut dosyanız çağrılırsa foo, işletim sistemi eşdeğerini yapacaktır.

/usr/bin/env node foo

envKomut, bu komut için bir bağımsız değişken aşağıdaki geçen, adı, komut satırında verilen bir komutu yürütür. Burada kullanılmasının nedeni , komutu envarayacak olmasıdır $PATH. Yani eğer nodeyüklenir /usr/local/bin/nodeve sahip /usr/local/binGözlerinde farklı $PATH, envkomut çağıracağı /usr/local/bin/node foo.

envKomutun temel amacı, değiştirilmiş bir ortamda başka bir komutu yürütmek, komutu çalıştırmadan önce belirtilen ortam değişkenlerini eklemek veya kaldırmaktır. Ancak ek bağımsız değişkenler olmadan, yalnızca komutu değiştirilmemiş bir ortamda çalıştırır, bu durumda ihtiyacınız olan tek şey budur.

Bu yaklaşımın bazı dezavantajları vardır. Modern Unix benzeri sistemlerin çoğunda var /usr/bin/env, ancak envkomutun farklı bir dizine kurulduğu eski sistemler üzerinde çalıştım . Bu mekanizmayı kullanarak geçebileceğiniz ek argümanlarda sınırlamalar olabilir. Kullanıcı ,node içinde komutu içeren dizine sahip değilse$PATH veya başka bir komut çağrılmışsa node, yanlış komutu çalıştırabilir veya hiç çalışmayabilir.

Diğer yaklaşımlar şunlardır:

  • Komut dosyasını farklı sistemler için gerektiği gibi güncelleyerek komutun kendisine #!giden tam yolu belirten bir satır kullanın node; veya
  • Çağırmak nodebağımsız değişken olarak Senaryonuzun ile komutu.

Hile hakkında daha fazla tartışma için bu soruya (ve cevabıma ) da bakın #!/usr/bin/env.

Bu arada, sistemimde (Linux Mint 17.2) /usr/bin/nodejs. Notlarıma göre, değiştirilen /usr/bin/nodeiçin /usr/bin/nodejsUbuntu 12.04 ve 12.10 arasında. #!/usr/bin/envHile ile değil bize yardım eder (bir sembolik falan benzer kurmak sürece).

GÜNCELLEME: mtraceur tarafından yapılan bir yorum şöyle diyor (yeniden biçimlendirilmiş):

Nodejs ve düğüm sorunu için bir geçici çözüm, dosyayı aşağıdaki altı satırla başlatmaktır:

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

Bu önce deneyecek nodejs, sonra deneyecek nodeve hata mesajlarını yalnızca ikisi de bulunamazsa yazdıracaktır. Bir açıklama bu yorumların kapsamı dışındadır, bu cevap sorunu gündeme getirdiğinden, herhangi birinin problemle başa çıkmasına yardımcı olma ihtimaline karşı burada bırakıyorum.

Son zamanlarda NodeJS kullanmadım. Umudum olmasıdır nodejsvs nodeBen ilk bu cevabı yayınlanmıştır beri sorun yıllarda giderilmiştir. Ubuntu 18.04 tarihinde, nodejspaket yükler /usr/bin/nodejssembolik bağ olarak /usr/bin/node. Daha eski bir işletim sisteminde (Ubuntu veya Linux Mint, hangisi olduğundan emin değilim), sembolik bağlantı olarak nodejs-legacysağlanan bir paket vardı . Tüm ayrıntıları doğru bildiğimin garantisi yok.nodenodejs


Şeylerin nedenini açıklayan çok kapsamlı bir cevap.
Suraj Jain

1
nodejsVs nodesorunu için bir çözüm , dosyayı aşağıdaki altı satırla başlatmaktır: 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) */. Bu önce deneyecek nodejs, sonra deneyecek nodeve hata mesajlarını yalnızca ikisi de bulunamazsa yazdıracaktır. Bir açıklama bu yorumların kapsamı dışındadır, bu cevap sorunu gündeme getirdiğinden, herhangi birinin problemle başa çıkmasına yardımcı olma ihtimaline karşı burada bırakıyorum.
mtraceur

@mtraceur: Yorumunuzu cevabıma ekledim. Neden -üzerine #!hat?
Keith Thompson

-İçinde #!/bin/sh -sağ komut adı veya göreli yol kabuk bir ile başlar görür o şartların son derece dar ve olası sette emin kabuk davranır yapar sadece alışkanlıktır -. (Ayrıca, evet, her ana akım dağıtımın nodebirincil ad olarak yeniden birleştiği görülüyor. Yorumumu yaparken kontrol etmek için araştırma yapmaya gitmedim, ancak bildiğim kadarıyla sadece Debian dağıtım soy ağacının kullanıldığını nodejsve görünüyor nodeDebian'ın yaptığı gibi hepsi de desteklemeye geri döndüler .)
mtraceur

Teknik olarak, ilk argüman olarak tek çizgi "seçeneklerin sonu" anlamına gelmiyordu - başlangıçta "kapat -xve -v" anlamına geliyordu , ancak erken Bourne beğenileri yalnızca ilk argümanı olası seçenekler olarak çözümlediğinden ve kabuk bu seçenekler kapalıyken başladığından , kabuğun orijinalinden beri komut dosyası adını ayrıştırmaya çalışmamasına neden olmak kötüye kullanılabilir ve bu nedenle davranış, uyumluluk nedenlerinden ötürü modern Bourne-benzerlerinde sürdürüldüğü için kötüye kullanılabilir. Bourne geçmişimi ve taşınabilirlik bilgilerimi doğru hatırlıyorsam.
mtraceur

0

Kısa cevap: Tercümana giden yoldur.

DÜZENLEME (Uzun Cevap): "düğüm" den önce eğik çizgi olmamasının nedeni, #! / Bin / 'in güvenilirliğini her zaman garanti edememenizdir. "/ Env" biti, komut dosyasını değiştirilmiş bir ortamda çalıştırarak ve yorumlayıcı programını daha güvenilir bir şekilde bulabilmesini sağlayarak programı daha çapraz platform yapar.

Mutlaka ihtiyacınız yoktur, ancak taşınabilirliği (ve profesyonelliği) sağlamak için kullanmak iyidir


1
/usr/bin/envBit ortamı değiştirmez. Bu, argüman olarak verilen başka bir komutu çağıran ve $PATHonu bulmak için arama yapan (çoğunlukla) bilinen bir konumdaki bir komuttur . Önemli olan nokta, #!satırın çağrılan komuta giden tam yolu gerektirmesidir ve sizin nerede nodekurulu olduğunu bilmeniz gerekmez .
Keith Thompson

Ben de bunu yapıyordum, açıkladığınız için teşekkürler!
Kuantum
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.