为什么#!/usr/bin/env bash 优于#!/bin/bash?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21612980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is #!/usr/bin/env bash superior to #!/bin/bash?
提问by spugm1r3
I've seen in a number of places, including recommendations on this site (What is the preferred Bash shebang?), to use #!/usr/bin/env bash
in preference to #!/bin/bash
. I've even seen one enterprising individual suggest using #!/bin/bash
was wrongand bash functionality would be lost by doing so.
我在很多地方都看到过,包括在这个网站上的推荐(首选 Bash shebang 是什么?),#!/usr/bin/env bash
优先使用#!/bin/bash
. 我什至看到一个有进取心的人建议使用#!/bin/bash
是错误的,这样做会丢失 bash 功能。
All that said, I use bash in a tightly controlled test environment where every drive in circulation is essentially a clone of a single master drive. I understand the portability argument, though it is not necessarily applicable in my case. Is there any other reason to prefer #!/usr/bin/env bash
over the alternatives and, assuming portability was a concern, is there any reason using it could break functionality?
综上所述,我在严格控制的测试环境中使用 bash,其中流通中的每个驱动器本质上都是单个主驱动器的克隆。我理解可移植性的论点,尽管它不一定适用于我的情况。是否有任何其他理由更喜欢#!/usr/bin/env bash
替代方案,假设便携性是一个问题,是否有任何理由使用它会破坏功能?
回答by zigg
#!/usr/bin/env
searches PATH
for bash
, and bash
is not always in /bin
, particularly on non-Linux systems. For example, on my OpenBSD system, it's in /usr/local/bin
, since it was installed as an optional package.
#!/usr/bin/env
搜索PATH
的bash
,而bash
不是总在/bin
,特别是在非Linux系统。例如,在我的 OpenBSD 系统上,它在 中/usr/local/bin
,因为它是作为可选包安装的。
If you are absolutely sure bash
is in /bin
and will always be, there's no harm in putting it directly in your shebang—but I'd recommend against it because scripts and programs all have lives beyond what we initially believe they will have.
如果您绝对确定bash
是/bin
并且将永远是,那么将它直接放在您的shebang 中并没有什么坏处——但我建议您不要这样做,因为脚本和程序的寿命都超出了我们最初认为的寿命。
回答by David W.
The standard location of bash is /bin
, and I suspect that's true on all systems. However, what if you don't like that version of bash? For example, I want to use bash 4.2, but the bash on my Mac is at 3.2.5.
bash 的标准位置是/bin
,我怀疑在所有系统上都是如此。但是,如果您不喜欢那个版本的 bash 怎么办?例如,我想使用 bash 4.2,但我的 Mac 上的 bash 是 3.2.5。
I could try reinstalling bash in /bin
but that may be a bad idea. If I update my OS, it will be overwritten.
我可以尝试重新安装 bash,/bin
但这可能是个坏主意。如果我更新我的操作系统,它将被覆盖。
However, I could install bash in /usr/local/bin/bash
, and setup my PATH to:
但是,我可以在 bash 中安装 bash /usr/local/bin/bash
,并将我的 PATH 设置为:
PATH="/usr/local/bin:/bin:/usr/bin:$HOME/bin"
Now, if I specify bash
, I don't get the old cruddy one at /bin/bash
, but the newer, shinier one at /usr/local/bin
. Nice!
现在,如果我指定bash
,我不会在 处得到旧的粗糙的/bin/bash
,而是在 处得到更新的、更闪亮的/usr/local/bin
。好的!
Except my shell scripts have that !# /bin/bash
shebang. Thus, when I run my shell scripts, I get that old and lousy version of bash that doesn't even have associative arrays.
除了我的shell脚本有那个!# /bin/bash
shebang。因此,当我运行我的 shell 脚本时,我得到了那个旧的、糟糕的 bash 版本,它甚至没有关联数组。
Using /usr/bin/env bash
will use the version of bash found in my PATH. If I setup my PATH, so that /usr/local/bin/bash
is executed, that's the bash that my scripts will use.
Using/usr/bin/env bash
将使用在我的 PATH 中找到的 bash 版本。如果我设置了我的 PATH,那么它/usr/local/bin/bash
就会被执行,这就是我的脚本将使用的 bash。
It's rare to see this with bash, but it is a lot more common with Perl and Python:
在 bash 中很少看到这种情况,但在 Perl 和 Python 中更常见:
- Certain Unix/Linux releases which focus on stabilityare sometimes way behind with the release of these two scripting languages. Not long ago, RHEL's Perl was at 5.8.8 -- an eight year old version of Perl! If someone wanted to use more modern features, you had to install your own version.
- Programs like Perlbrew and Pythonbrew allow you to install multiple versions of these languages. They depend upon scripts that manipulate your PATH to get the version you want. Hard coding the path means I can't run my script under brew.
- It wasn't that long ago (okay, it was long ago) that Perl and Python were not standard packages included in most Unix systems. That meant you didn't know where these two programs were installed. Was it under
/bin
?/usr/bin
?/opt/bin
? Who knows? Using#! /usr/bin/env perl
meant I didn't have to know.
- 某些专注于稳定性的Unix/Linux 版本有时会落后于这两种脚本语言的发布。不久前,RHEL 的 Perl 是 5.8.8 —— 一个八年前的 Perl 版本!如果有人想使用更现代的功能,您必须安装自己的版本。
- Perlbrew 和 Pythonbrew 等程序允许您安装这些语言的多个版本。它们依赖于操纵您的 PATH 的脚本来获得您想要的版本。对路径进行硬编码意味着我无法在brew下运行我的脚本。
- 不久之前(好吧,很久以前)Perl 和 Python 还不是大多数 Unix 系统中包含的标准包。这意味着您不知道这两个程序的安装位置。是在下
/bin
吗?/usr/bin
?/opt/bin
? 谁知道?使用#! /usr/bin/env perl
意味着我不必知道。
And Now Why You Shouldn't Use #! /usr/bin/env bash
现在为什么你不应该使用 #! /usr/bin/env bash
When the path is hardcoded in the shebang, I have to run with that interpreter. Thus, #! /bin/bash
forces me to use the default installed version of bash. Since bash features are very stable (try running a 2.x version of a Python script under Python 3.x) it's very unlikely that my particular BASH script will not work, and since my bash script is probably used by this system and other systems, using a non-standard version of bash may have undesired effects. It is very likely I want to make sure that the stable standard version of bash is used with my shell script. Thus, I probably want to hard code the path in my shebang.
当路径在 shebang 中被硬编码时,我必须使用该解释器运行。因此,#! /bin/bash
迫使我使用默认安装的 bash 版本。由于 bash 功能非常稳定(尝试在 Python 3.x 下运行 2.x 版本的 Python 脚本),因此我的特定 BASH 脚本不太可能无法运行,而且我的 bash 脚本可能已被该系统和其他系统使用,使用非标准版本的 bash 可能会产生不良影响。我很可能想确保 bash 的稳定标准版本与我的 shell 脚本一起使用。因此,我可能想对我的shebang 中的路径进行硬编码。
回答by Sean Perry
For invoking bash
it is a little bit of overkill. Unless you have multiple bash
binaries like your own in ~/bin but that also means your code depends on $PATH having the right things in it.
调用bash
它有点矫枉过正。除非您bash
在 ~/bin 中有多个像您自己的二进制文件,但这也意味着您的代码取决于 $PATH 中是否包含正确的内容。
It is handy for things like python
though. There are wrapper scripts and environments which lead to alternative python
binaries being used.
不过,这对于诸如此类的事情来说很方便python
。存在导致使用替代python
二进制文件的包装脚本和环境。
But nothing is lost by using the exact path to the binary as long as you are sure it is the binary you really want.
但是,只要您确定它是您真正想要的二进制文件,使用二进制文件的确切路径不会丢失任何内容。
回答by James Ko
There are a lot of systems that don't have Bash in /bin
, FreeBSD and OpenBSD just to name a few. If your script is meant to be portable to many different Unices, you may want to use #!/usr/bin/env bash
instead of #!/bin/bash
.
有很多系统没有 Bash in /bin
、FreeBSD 和 OpenBSD,仅举几例。如果你的脚本是指可以移植到许多不同的Unix系统,你可能需要使用#!/usr/bin/env bash
替代#!/bin/bash
。
Note that this does not hold true for sh
; for Bourne-compliant scripts I exclusively use #!/bin/sh
, since I think pretty much every Unix in existence has sh
in /bin
.
请注意,这不适用于sh
; 对于兼容的Bourne脚本,我只使用#!/bin/sh
,因为我觉得几乎每一个Unix的存在具有sh
的/bin
。
回答by kta
#!/usr/bin/env bash
is definitely better because it finds the bash executable path from your system environment variable.
绝对更好,因为它可以从您的系统环境变量中找到 bash 可执行文件路径。
Go to your Linux shell and type
转到您的 Linux shell 并键入
env
It will print all your environment variables.
它将打印您所有的环境变量。
Go to your shell script and type
转到您的 shell 脚本并键入
echo $BASH
It will print your bash path (according to the environment variable list) that you should use to build your correct shebang path in your script.
它将打印您的 bash 路径(根据环境变量列表),您应该使用该路径在脚本中构建正确的 shebang 路径。
回答by Mihir
I would prefer wrapping the main program in a script like below to check all bash
available on system. Better to have more control on the version it uses.
我更喜欢将主程序包装在如下脚本中以检查bash
系统上的所有可用程序。最好对其使用的版本有更多的控制。
#! /usr/bin/env bash
# This script just chooses the appropriate bash
# installed in system and executes testcode.main
readonly DESIRED_VERSION="5"
declare all_bash_installed_on_this_system
declare bash
if [ "${BASH_VERSINFO}" -ne "${DESIRED_VERSION}" ]
then
found=0
all_bash_installed_on_this_system="$(\
awk -F'/' '$NF == "bash"{print}' "/etc/shells"\
)"
for bash in $all_bash_installed_on_this_system
do
versinfo="$( $bash -c 'echo ${BASH_VERSINFO}' )"
[ "${versinfo}" -eq "${DESIRED_VERSION}" ] && { found=1 ; break;}
done
if [ "${found}" -ne 1 ]
then
echo "${DESIRED_VERSION} not available"
exit 1
fi
fi
$bash main_program "$@"