“#!/ usr / bin / env bash”和“#!/ usr / bin / bash”有什麼區別?

本文翻譯自:What is the difference between “#!/usr/bin/env bash” and “#!/usr/bin/bash”?

In the header of a bash script, what's the difference between those two statements ? bash腳本的標題中,這兩個語句之間的區別是什麼?

  1. #!/usr/bin/env bash

  2. #!/usr/bin/bash

When I tried to see the env man page, I get this definition: 當我試圖看到env手冊頁時,我得到了這個定義:

 env - run a program in a modified environment

What does it mean? 這是什麼意思?


#1樓

參考:https://stackoom.com/question/16fJi/usr-bin-env-bash-和-usr-bin-bash-有什麼區別


#2樓

Instead of explicitly defining the path to the interpreter as in /usr/bin/bash/ , by using the env command, the interpreter is searched for and launched from wherever it is first found. 不是通過使用env命令在/usr/bin/bash/中明確定義解釋器的路徑,而是從首次找到解釋器的任何地方搜索並啓動解釋器。 This has both upsides and downsides 有好處和缺點


#3樓

Using #!/usr/bin/env NAME makes the shell search for the first match of NAME in the $PATH environment variable. 使用#!/usr/bin/env NAME使shell在$ PATH環境變量中搜索NAME的第一個匹配項。 It can be useful if you aren't aware of the absolute path or don't want to search for it. 如果您不知道絕對路徑或不想搜索它,它會很有用。


#4樓

Running a command through /usr/bin/env has the benefit of looking for whatever the default version of the program is in your current env ironment. 通過運行一個命令/usr/bin/env有尋找任何程序的默認版本是在當前的ENV ironment利益。

This way, you don't have to look for it in a specific place on the system, as those paths may be in different locations on different systems. 這樣,您不必在系統上的特定位置查找它,因爲這些路徑可能位於不同系統上的不同位置。 As long as it's in your path, it will find it. 只要它在你的道路上,它就會找到它。

One downside is that you will be unable to pass more than one argument (eg you will be unable to write /usr/bin/env awk -f ) if you wish to support Linux, as POSIX is vague on how the line is to be interpreted, and Linux interprets everything after the first space to denote a single argument. 一個缺點是,如果你想支持Linux,你將無法傳遞多個參數(例如,你將無法編寫/usr/bin/env awk -f ),因爲POSIX對於該線路是如何模糊的解釋,並且Linux在第一個空格之後解釋所有內容以表示單個參數。 You can use /usr/bin/env -S on some versions of env to get around this, but then the script will become even less portable and break on fairly recent systems (eg even Ubuntu 16.04 if not later). 您可以在某些版本的env上使用/usr/bin/env -S來解決這個問題,但隨後腳本將變得更不便攜並且在相當近期的系統上中斷(例如,如果不是更晚的話,甚至是Ubuntu 16.04)。

Another downside is that since you aren't calling an explicit executable, it's got the potential for mistakes, and on multiuser systems security problems (if someone managed to get their executable called bash in your path, for example). 另一個缺點是,由於您沒有調用顯式可執行文件,因此可能存在錯誤,並且存在多用戶系統安全問題(例如,如果有人設法在您的路徑中獲取名爲bash的可執行文件)。

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

In some situations, the first may be preferred (like running python scripts with multiple versions of python, without having to rework the executable line). 在某些情況下,第一個可能是首選(如運行python腳本與多個版本的python,而不必重做可執行行)。 But in situations where security is the focus, the latter would be preferred, as it limits code injection possibilities. 但是在以安全性爲重點的情況下,後者將是首選,因爲它限制了代碼注入的可能性。


#5樓

I find it useful, because when I didn't know about env, before I started to write script I was doing this: 我發現它很有用,因爲當我不知道env時,在我開始編寫腳本之前我就是這樣做的:

type nodejs > scriptname.js #or any other environment

and then I was modifying that line in the file into shebang. 然後我將文件中的那一行修改爲shebang。
I was doing this, because I didn't always remember where is nodejs on my computer -- /usr/bin/ or /bin/, so for me env is very useful. 我這樣做,因爲我並不總是記得我的計算機上的nodejs在哪裏 - / usr / bin /或/ bin /,所以對我來說env非常有用。 Maybe there are details with this, but this is my reason 也許這裏有細節,但這是我的理由


#6樓

If the shell scripts start with #!/bin/bash , they will always run with bash from /bin . 如果shell腳本以#!/bin/bash開頭,它們將始終使用來自/bin bash運行。 If they however start with #!/usr/bin/env bash , they will search for bash in $PATH and then start with the first one they can find. 然而,如果他們以#!/usr/bin/env bash開頭,他們將在$PATH搜索bash ,然後從他們可以找到的第一個開始。

Why would this be useful? 爲什麼這會有用? Assume you want to run bash scripts, that require bash 4.x or newer, yet your system only has bash 3.x installed and currently your distribution doesn't offer a newer version or you are no administrator and cannot change what is installed on that system. 假設您要運行需要bash 4.x或更新版本的bash腳本,但您的系統只安裝了bash 3.x,目前您的發行版沒有提供更新的版本,或者您不是管理員,也無法更改安裝的內容那個系統。

Of course, you can download bash source code and build your own bash from scratch, placing it to ~/bin for example. 當然,您可以從頭開始下載bash源代碼並構建自己的bash,例如將它放在~/bin中。 And you can also modify your $PATH variable in your .bash_profile file to include ~/bin as the first entry ( PATH=$HOME/bin:$PATH as ~ will not expand in $PATH ). 您還可以在.bash_profile文件中修改$PATH變量,以包含~/bin作爲第一個條目( PATH=$HOME/bin:$PATH as ~將不會在$PATH展開)。 If you now call bash , the shell will first look for it in $PATH in order, so it starts with ~/bin , where it will find your bash . 如果你現在調用bash ,shell將首先在$PATH中按順序查找它,所以它以~/bin開頭,它會找到你的bash Same thing happens if scripts search for bash using #!/usr/bin/env bash , so these scripts would now be working on your system using your custom bash build. 如果腳本使用#!/usr/bin/env bash搜索bash則會發生同樣的事情,因此這些腳本現在將使用您的自定義bash構建在您的系統上運行。

One downside is, that this can lead to unexpected behavior, eg same script on the same machine may run with different interpreters for different environments or users with different search paths, causing all kind of headaches. 一個缺點是,這可能導致意外行爲,例如,同一臺機器上的相同腳本可能針對不同的環境或具有不同搜索路徑的用戶使用不同的解釋器運行,從而導致各種令人頭疼的問題。

The biggest downside with env is that some systems will only allow one argument, so you cannot do this #!/usr/bin/env <interpreter> <arg> , as the systems will see <interpreter> <arg> as one argument (they will treat it as if the expression was quoted) and thus env will search for an interpreter named <interpreter> <arg> . env最大的缺點是有些系統只允許一個參數,所以你不能這樣做#!/usr/bin/env <interpreter> <arg> ,因爲系統會將<interpreter> <arg>視爲一個參數(他們會把它看作是引用的表達式,因此env將搜索名爲<interpreter> <arg> Note that this is not a problem of the env command itself, which always allowed multiple parameters to be passed through but with the shebang parser of the system that parses this line before even calling env . 請注意,這不是env命令本身的問題,它始終允許傳遞多個參數,但使用系統的shebang解析器,甚至在調用env之前解析此行。 Meanwhile this has been fixed on most systems but if your script wants to be ultra portable, you cannot rely that this has been fixed on the system you will be running. 與此同時,這已在大多數系統上得到修復,但如果您的腳本想要超便攜,則不能依賴於已在您運行的系統上修復此腳本。

It can even have security implications, eg if sudo was not configured to clean environment or $PATH was excluded from clean up. 它甚至可能具有安全隱患,例如,如果sudo未配置爲清理環境或$PATH被排除在清理之外。 Let me demonstrate this: 讓我演示一下:

Usually /bin is a well protected place, only root is able to change anything there. 通常/bin是一個受到良好保護的地方,只有root能夠在那裏改變任何東西。 Your home directory is not, though, any program you run is able to make changes to it. 但是,您的主目錄不是,您運行的任何程序都可以對其進行更改。 That means malicious code could place a fake bash into some hidden directory, modify your .bash_profile to include that directory in your $PATH , so all scripts using #!/usr/bin/env bash will end up running with that fake bash . 這意味着惡意代碼可能會將僞造的bash放入某個隱藏目錄,修改.bash_profile以將該目錄包含在$PATH ,因此使用#!/usr/bin/env bash所有腳本最終都將使用該僞造的bash運行。 If sudo keeps $PATH , you are in big trouble. 如果sudo保持$PATH ,你就會遇到大麻煩。

Eg consider a tool creates a file ~/.evil/bash with the following content: 例如,考慮一個工具創建一個文件~/.evil/bash其中包含以下內容:

#!/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 "$@"

Let's make a simple script sample.sh : 讓我們製作一個簡單的腳本sample.sh

#!/usr/bin/env bash

echo "Hello World"

Proof of concept (on a system where sudo keeps $PATH ): 概念證明(在sudo保留$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

Usually the classic shells should all be located in /bin and if you don't want to place them there for whatever reason, it's really not an issue to place a symlink in /bin that points to their real locations (or maybe /bin itself is a symlink), so I would always go with #!/bin/sh and #!/bin/bash . 通常,經典shell應該都位於/bin ,如果你不想因爲某種原因將它們放在那裏,那麼在/bin中放置指向它們真實位置的符號鏈接(或者/bin本身)真的不是問題。是一個符號鏈接),所以我總是選擇#!/bin/sh#!/bin/bash There's just too much that would break if these wouldn't work anymore. 如果這些不再起作用,那就太多了會破壞。 It's not that POSIX would require these position (POSIX does not standardize path names and thus it doesn't even standardize the shebang feature at all) but they are so common, that even if a system would not offer a /bin/sh , it would probably still understand #!/bin/sh and know what to do with it and may it only be for compatibility with existing code. 並不是POSIX會要求這些位置(POSIX沒有標準化路徑名,因此它甚至根本沒有標準化shebang功能)但它們是如此常見,即使系統不提供/bin/sh ,它也是如此可能仍然會理解#!/bin/sh並知道該如何處理它可能只是爲了與現有代碼兼容。

But for more modern, non standard, optional interpreters like Perl, PHP, Python, or Ruby, it's not really specified anywhere where they should be located. 但是對於更現代的,非標準的,可選的解釋器,如Perl,PHP,Python或Ruby,它並沒有真正指定它們應該位於何處。 They may be in /usr/bin but they may as well be in /usr/local/bin or in a completely different hierarchy branch ( /opt/... , /Applications/... , etc.). 它們可能位於/usr/bin但它們也可能位於/usr/local/bin或完全不同的層次結構分支( /opt/.../Applications/...等)中。 That's why these often use the #!/usr/bin/env xxx shebang syntax. 這就是爲什麼這些經常使用#!/usr/bin/env xxx shebang語法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章