“#! / Usr / bin / env bash” ve “#! / Usr / bin / bash” arasındaki fark nedir?


372

Bash betiğinin başlığında, bu iki ifade arasındaki fark nedir:

  1. #!/usr/bin/env bash

  2. #!/usr/bin/bash

env Man sayfasına danıştığımda şu tanımı alıyorum:

 env - run a program in a modified environment

Bunun anlamı ne?



6
Kim bana bu sorunun neden kapalı olduğunu söyleyebilir, "programlama veya yazılım geliştirme ile ilgili" değil?
tarrsalah

1
Ben konu dışı değil katılıyorum ama gibi muhtemelen diğer bazı soruların bir kopyası bu bir .
Keith Thompson

16
Bu soru konu dışı olarak işaretlenmemelidir. Sadece "konuyla ilgili" olarak işaretlemek için 3000'in üzerinde puanı olan 5 kişiye ihtiyaç duyuyor ve yeniden açılabilir. Bu, özellikle programlama ile ilgili bir sorudur.
Danijel-James W

3
Şok oldum. Linux belgelerinin totolojilere uygun olduğunu görmek şok oldu. xkcd.com/703 git-man-page-generator.lokaltog.net
allyourcode

Yanıtlar:


323

Bir komut through Koşu /usr/bin/envprogramı varsayılan sürümü mevcut ne varsa arayan yararı vardır env ironment.

Bu şekilde, sistemdeki belirli bir yerde aramak zorunda kalmazsınız, çünkü bu yollar farklı sistemlerde farklı yerlerde olabilir. Yolunda olduğu sürece onu bulacak.

Tek dezavantajı, /usr/bin/env awk -fLinux'u desteklemek istiyorsanız birden fazla argümanı (örneğin yazamayacaksınız ) geçemeyeceğinizdir , çünkü POSIX satırın nasıl yorumlanacağı konusunda belirsizdir ve Linux ilkinden sonra her şeyi yorumlar tek bir argümanı belirtmek için boşluk. Bu /usr/bin/env -Ssorunun envüstesinden gelmek için bazı sürümlerinde kullanabilirsiniz , ancak komut dosyası daha az taşınabilir hale gelecek ve oldukça yeni sistemlere zarar verecektir (örneğin, daha sonra değilse Ubuntu 16.04 bile).

Başka bir dezavantajı, açık bir yürütülebilir dosya çağırmamanızdan dolayı, hata potansiyeli ve çok kullanıcılı sistemlerin güvenlik sorunları ( bashörneğin, yürütülebilir dosyalarınızı yolunuza çağırmayı başarmışsa ).

#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

Bazı durumlarda, birincisi tercih edilebilir (çalıştırılabilir satırın yeniden çalışmasına gerek kalmadan, python'un birden çok sürümüyle python betikleri çalıştırmak gibi). Ancak güvenliğin odaklandığı durumlarda, kod enjeksiyon olanaklarını sınırladığı için ikincisi tercih edilecektir.


22
Diğer bir dezavantaj, tercümana ek bir argüman iletememenizdir.
Keith Thompson

1
@KeithThompson: Yanlış bilgi .. / usr / bin / env kullanarak alttaki tercümana seçenekler iletebilirsiniz.
Gaurav Agarwal

4
@GauravAgarwal: Sistemimde değil. Sadece bu tek satırı içeren bir komut dosyası: #!/usr/bin/env echo Helloyakınır: /usr/bin/env: echo Hello: No such file or directory. Görünüşe göre echo Hellotek bir argüman olarak davranıyor /usr/bin/env.
Keith Thompson

1
@ AndréLaszlo: envKomut kesinlikle argümanların komuta iletilmesine izin verir. Sorun #!satırın anlambilimidir ve bu çekirdeğe bağlıdır. Son Linux çekirdekleri böyle şeylere izin verir #!/usr/bin/env command args, ancak eski Linux çekirdekleri ve diğer sistemler buna izin vermez.
Keith Thompson

1
Neden kod bloğunda geri tıklamalar var? Çıkarılmamalılar mı?
Benjamin W.

64

Kullanarak #!/usr/bin/env NAME$ PATH ortam değişkenindeki NAME öğesinin ilk eşleşmesi için kabuk araması yapar. Mutlak yolun farkında değilseniz veya aramak istemiyorsanız yararlı olabilir.


9
En azından env'in nerede olduğunu bilmelisin :).
ᐅ devrimbaris

1
Mükemmel cevap. "Sistem yapılandırmanıza göre programı seçer" demek yerine env shebang'ın ne yaptığını açıklar
De Novo

13

Tercümanın yolunu açık olarak tanımlamak yerine /usr/bin/bash/, env komutunu kullanarak, tercüman aranır ve ilk bulunduğu yerden başlatılır. Bu hem yukarı hem de aşağı yönlü


Çoğu sistemde, bunlar işlevsel olarak aynı olacaktır, ancak bash ve env yürütülebilir dosyalarınızın konumuna bağlıdır. Ancak bunun ortam değişkenlerini nasıl etkileyeceğinden emin değilim.
safay

2
"Tercümanı env kullanmadan, tercümana tam yol vererek belirtmek mümkündür. Bir sorun, farklı bilgisayar sistemlerinde kesin yolun farklı olabilmesidir. Bunun yerine env yerine tercüman aranır ve Bu, komut dosyasını daha taşınabilir hale getirir, ancak aynı zamanda çalıştırılabilir arama yolundaki her dizinde bir eşleşme aradığından yanlış yorumlayıcının seçilme riskini de artırır. env ikilisine giden yol da her makine için farklı olabilir. "- Vikipedi
Mike Clark

10

Kabuk komut ile başlarsanız #!/bin/bash, hep birlikte çalışacak bashdan /bin. Onlar ancak başlarsanız #!/usr/bin/env bash, onlar arayacaktır bashiçinde $PATHve sonra da bulabilirsiniz ilkinden başlar.

Bu neden faydalı olabilir? bashBash 4.x veya daha bashyeni bir sürüm gerektiren komut dosyalarını çalıştırmak istediğinizi varsayalım , ancak sisteminizde yalnızca 3.x yüklü ve şu anda dağıtımınız daha yeni bir sürüm sunmuyor veya yönetici değilseniz ve bu sistemde yüklü olanı değiştiremezsiniz .

Tabii ki, bash kaynak kodunu indirebilir ve ~/binörneğin kendi bash'ınızı sıfırdan oluşturabilirsiniz. Ve ayrıca değiştirebilir $PATHsenin içinde değişken .bash_profiledahil etmek dosyanın ~/binilk girişi (aynı PATH=$HOME/bin:$PATHşekilde ~genişleyecek olmaz $PATH). Şimdi ararsanız bash, kabuk ilk önce $PATHsırayla arayacaktır , bu yüzden ile ~/binnerede bulacağınızla başlar bash. Komut dosyaları bashkullanmak için arama yaparsa aynı şey olur #!/usr/bin/env bash, bu nedenle bu komut dosyaları artık özel bashderlemenizi kullanarak sisteminizde çalışır .

Bunun bir dezavantajı, bunun beklenmedik davranışlara yol açabilmesidir, örneğin aynı makinedeki aynı komut dosyası, farklı ortamlar veya farklı arama yolları olan kullanıcılar için farklı yorumlayıcılarla çalışarak her türlü baş ağrısına neden olabilir.

En büyük dezavantajı env, bazı sistemlerin sadece bir argümana izin vereceğidir, bu yüzden #!/usr/bin/env <interpreter> <arg>sistemler <interpreter> <arg>tek bir argüman olarak göreceğinden (ifade alıntılanmış gibi davranacak) ve böylece envadlı bir tercüman arayacaktır <interpreter> <arg>. Bu envkomutun her zaman birden fazla parametrenin geçmesine izin veren bir sorun değil , hatta aramadan önce bu hattı ayrıştıran sistemin shebang ayrıştırıcısı ile ilgili bir sorun olduğunu unutmayın env. Bu arada bu çoğu sistemde düzeltildi, ancak betiğiniz ultra taşınabilir olmak istiyorsa, bunun çalıştıracağınız sistemde düzeltildiğine güvenemezsiniz.

Örneğin sudo, çevreyi temizleyecek şekilde yapılandırılmamışsa veya temizlenmemesi $PATHdışında da güvenlik etkileri olabilir . Bunu göstereyim:

Genellikle /biniyi korunan bir yer, sadece rootorada herhangi bir şeyi değiştirebilir. Ancak ana dizininiz çalıştırdığınız herhangi bir programda değişiklik yapamaz. Bu, kötü amaçlı kodun bashgizli bir dizine sahte yerleştirilebileceği .bash_profile, dizininizi o dizine ekleyecek şekilde değiştirebileceğiniz anlamına gelir $PATH, böylece kullanılan tüm komut dosyaları #!/usr/bin/env bashbu sahte ile çalışacaktır bash. Eğer sudotutarsa $PATH, başınız büyük belada.

Örneğin, bir aracın ~/.evil/bashaşağıdaki içeriğe sahip bir dosya oluşturduğunu düşünün :

#!/bin/bash

if [ $EUID -eq 0 ]; then
  echo "All your base are belong to us..."
  # We are root - do whatever you want to do
fi

/bin/bash "$@"

Basit bir komut dosyası yapalım sample.sh:

#!/usr/bin/env bash

echo "Hello World"

Kavram kanıtı ( sudosakladığı bir sistemde $PATH):

$ ./sample.sh
Hello World

$ sudo ./sample.sh
Hello World

$ export PATH="$HOME/.evil:$PATH"

$ ./sample.sh
Hello World

$ sudo ./sample.sh
All your base are belong to us...
Hello World

Genellikle klasik mermilerin hepsi yer almalıdır /binve bunları herhangi bir nedenden dolayı oraya yerleştirmek istemiyorsanız /bin, gerçek konumlarına işaret eden bir işaret eklemek (veya belki /binde bir işaret bağlantısıdır), bu yüzden Her zaman #!/bin/shve ile giderdim #!/bin/bash. Artık işe yaramazsa kırılacak çok fazla şey var. POSIX bu konumu gerektirmez (POSIX yol adlarını standartlaştırmaz ve bu nedenle shebang özelliğini hiç standartlaştırmaz), ancak çok yaygındır, bir sistem sunmasa bile /bin/sh, muhtemelen hala anlardı #!/bin/shve bununla ne yapılacağını bilir ve yalnızca mevcut kodla uyumluluk için olabilir.

Ancak Perl, PHP, Python veya Ruby gibi daha modern, standart olmayan, isteğe bağlı tercümanlar için, bulunmaları gereken hiçbir yerde belirtilmemiş. Bunlar olabilir /usr/binama onlar da olabilir /usr/local/binveya tamamen farklı bir hiyerarşi dalı (içinde /opt/..., /Applications/...vs.). Bu yüzden bunlar genellikle #!/usr/bin/env xxxshebang sözdizimini kullanır.


4

Yararlı buluyorum, çünkü env hakkında bilmediğimde, senaryo yazmaya başlamadan önce bunu yapıyordum:

type nodejs > scriptname.js #or any other environment

ve sonra dosyadaki satırı değiştirerek değiştiriyordum.
Bunu yapıyordum, çünkü bilgisayarımda nodejs nerede olduğunu hatırlamıyordum - / usr / bin / veya / bin /, bu yüzden benim enviçin çok faydalı. Belki bununla ilgili ayrıntılar var, ama bu benim nedenim

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.