“#!/ 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语法。

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