Bash betiğinin başlığında, bu iki ifade arasındaki fark nedir:
#!/usr/bin/env bash
#!/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?
Bash betiğinin başlığında, bu iki ifade arasındaki fark nedir:
#!/usr/bin/env bash
#!/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?
Yanıtlar:
Bir komut through Koşu /usr/bin/env
programı 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 -f
Linux'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 -S
sorunun 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.
#!/usr/bin/env echo Hello
yakınır: /usr/bin/env: echo Hello: No such file or directory
. Görünüşe göre echo Hello
tek bir argüman olarak davranıyor /usr/bin/env
.
env
Komut 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.
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.
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ü
Kabuk komut ile başlarsanız #!/bin/bash
, hep birlikte çalışacak bash
dan /bin
. Onlar ancak başlarsanız #!/usr/bin/env bash
, onlar arayacaktır bash
içinde $PATH
ve sonra da bulabilirsiniz ilkinden başlar.
Bu neden faydalı olabilir? bash
Bash 4.x veya daha bash
yeni 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 $PATH
senin içinde değişken .bash_profile
dahil etmek dosyanın ~/bin
ilk girişi (aynı PATH=$HOME/bin:$PATH
şekilde ~
genişleyecek olmaz $PATH
). Şimdi ararsanız bash
, kabuk ilk önce $PATH
sırayla arayacaktır , bu yüzden ile ~/bin
nerede bulacağınızla başlar bash
. Komut dosyaları bash
kullanmak için arama yaparsa aynı şey olur #!/usr/bin/env bash
, bu nedenle bu komut dosyaları artık özel bash
derlemenizi 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 env
adlı bir tercüman arayacaktır <interpreter> <arg>
. Bu env
komutun 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 $PATH
dışında da güvenlik etkileri olabilir . Bunu göstereyim:
Genellikle /bin
iyi korunan bir yer, sadece root
orada 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 bash
gizli 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 bash
bu sahte ile çalışacaktır bash
. Eğer sudo
tutarsa $PATH
, başınız büyük belada.
Örneğin, bir aracın ~/.evil/bash
aş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ı ( sudo
sakladığı 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 /bin
ve bunları herhangi bir nedenden dolayı oraya yerleştirmek istemiyorsanız /bin
, gerçek konumlarına işaret eden bir işaret eklemek (veya belki /bin
de bir işaret bağlantısıdır), bu yüzden Her zaman #!/bin/sh
ve 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/sh
ve 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/bin
ama onlar da olabilir /usr/local/bin
veya tamamen farklı bir hiyerarşi dalı (içinde /opt/...
, /Applications/...
vs.). Bu yüzden bunlar genellikle #!/usr/bin/env xxx
shebang sözdizimini kullanır.
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 env
için çok faydalı. Belki bununla ilgili ayrıntılar var, ama bu benim nedenim