在Bash脚本的头文件中,这两个语句的区别是什么:

#!/usr/bin/env bash #!/usr/bin/bash

当我查阅env手册页时,我得到了这样的定义:

 env - run a program in a modified environment

这是什么意思?


当前回答

我发现它很有用,因为当我不知道env的时候,在我开始写脚本之前,我是这样做的:

type nodejs > scriptname.js #or any other environment

然后我将文件中的这一行修改为shebang。 我这样做是因为我不总是记得nodejs在我的计算机上的位置- /usr/bin/或/bin/,所以对我来说env非常有用。也许这里面有细节,但这就是我的理由

其他回答

我发现它很有用,因为当我不知道env的时候,在我开始写脚本之前,我是这样做的:

type nodejs > scriptname.js #or any other environment

然后我将文件中的这一行修改为shebang。 我这样做是因为我不总是记得nodejs在我的计算机上的位置- /usr/bin/或/bin/,所以对我来说env非常有用。也许这里面有细节,但这就是我的理由

使用# !/usr/bin/env NAME使shell搜索$PATH环境变量中NAME的第一个匹配项。如果您不知道绝对路径或不想搜索它,它会很有用。

一个原因是它可以在Linux和BSD之间移植。

通过使用env命令而不是显式地将解释器的路径定义为/usr/bin/bash/,解释器将从第一次找到它的地方搜索并启动。这既有好处也有坏处

如果shell脚本以#!/bin/bash,它们将始终从/bin运行bash。但是,如果它们以#!/usr/bin/env bash,他们将在$PATH中搜索bash,然后从他们能找到的第一个开始。

为什么这有用呢?假设您想运行bash脚本,需要bash 4。X或更新版本,但您的系统只有bash 3。X已安装,但当前您的发行版没有提供更新的版本,或者您不是管理员,无法更改系统上安装的内容。

Of course, you can download bash source code and build your own bash from scratch, placing it to ~/bin for example. 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). 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. 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.

一个缺点是,这可能会导致意想不到的行为,例如,同一台机器上的相同脚本可能在不同的环境中使用不同的解释器运行,或者使用不同的搜索路径的用户,这会导致各种各样的头痛。

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>. 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. 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.

它甚至可能有安全隐患,例如,如果sudo没有配置为清理环境或$PATH被排除在清理之外。让我来演示一下:

通常/bin是一个保护良好的地方,只有root才能在那里更改任何内容。但是,您的主目录不是,您运行的任何程序都能够对它进行更改。这意味着恶意代码可以在一些隐藏目录中放置一个假bash,修改您的.bash_profile以将该目录包含在您的$PATH中,因此所有脚本都使用#!/usr/bin/env bash最终会运行这个假bash。如果sudo保留$PATH,您就有大麻烦了。

例如,考虑一个工具创建一个文件~/。邪恶/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 "$@"

让我们创建一个简单的脚本sample.sh:

#!/usr/bin/env bash

echo "Hello World"

概念证明(在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. 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.

但是对于更现代的、非标准的、可选的解释器,如Perl、PHP、Python或Ruby,实际上并没有指定它们应该放在哪里。它们可能在/usr/bin中,但也可能在/usr/local/bin中,或者在一个完全不同的层次结构分支中(/opt/…/应用程序/……等)。这就是为什么它们经常使用#!/usr/bin/env XXX shebang语法。