为什么#!/ usr / bin / env bash优于#!/ bin / bash?


212

我已经在很多地方看到过,包括本网站上的建议(首选Bash shebang是什么?),它们#!/usr/bin/env bash优先于使用#!/bin/bash。我什至已经看到一个有进取心的个人认为使用#!/bin/bash错误的,这样做会丢失bash功能。

综上所述,我在严格控制的测试环境中使用bash,其中每个流通的驱动器实质上都是单个主驱动器的克隆。我理解可移植性参数,尽管它不一定适用于我的情况。是否还有其他理由要优先#!/usr/bin/env bash考虑其他选择,并且考虑到可移植性,是否有任何理由使用它会破坏功能?


7
不一定更好。在unix.stackexchange.com上看到此问题我的答案。(我将关闭此文件进行重复投票,但我认为您不能在各个网站上都这样做。)
Keith Thompson

2
除了@zigg的答案,env可能不在/usr/bin。Shebang的评论完全是个坏主意,恕我直言。如果您的默认脚本解释器不处理shebang注释,则仅是注释。但是,如果您知道脚本解释器可以处理shebang注释,并且知道bash的路径,则没有理由不使用其绝对路径来调用它,除非该路径太长(不太可能),否则您可能会移植脚本到/ bin中没有bash的系统。再说一次,我前面提到的警告适用于这种情况,因为它涉及可移植性。

1
@KeithThompson,感谢您的链接。在发布问题之前,我对答案的搜索可能有点狭窄。我从所有这些方面得到的收获是:(1)linux / unix / posix / etc ...是灰色的,(2)声称绝对拥有正确答案的任何人对于他们的特定情况绝对具有正确答案。
spugm1r3

3
POSIX / Unix中许多事物的行为已得到很好的定义。位置并不总是那么清晰。必须存在某种事物,例如/etc/bin/shbash是大多数类似Unix的系统的附件。只有Linux bash可以保证存在,/bin并且很可能也链接为/bin/sh。自从Linux成为许多人事实上的现代Unix以来,人们已经忘记了可能存在Linux以外的系统的事实。在我下面的回答中,我假设使用Linux,因为您说bash。我使用过的许多BSD盒甚至都没有安装。
肖恩·佩里

2
@Keith-对于Bash(与其他问题中的Python相反)... OpenBSD没有/bin/bash。默认情况下未安装Bash。如果需要,您必须pkg install bash。安装后,它位于/usr/local/bin/bash/bin/bashOpenBSD上没有安装任何东西。的家当#!/bin/bash就会报错,并且#!/usr/bin/env bash一定会成功。
jww

Answers:


229

#!/usr/bin/env搜索PATHbash,而bash不是总在/bin,特别是在非Linux系统。例如,在我的OpenBSD系统上,它位于中/usr/local/bin,因为它是作为可选软件包安装的。

如果你是绝对肯定的bash/bin并将永远是,有没有害处把它直接在你的家当,但我建议反对,因为脚本和程序都超出了我们最初认为他们将不得不生活。


29
怎么样env的位置?POSIX不会强制执行。
Julio Guerra

1
@JulioGuerra很像拥有一个/usr/lib/sendmail(或更近的/usr/sbin/sendmail)二进制文件来处理邮件,这是类Unix系统的最大利益,/usr/bin/env因为env shebang是一种常见的做法。这是事实上的标准接口。
zigg

8
@zigg真是UN * X ... <-:我的意思是,拥有的标准位置符合他们的最大利益env,但不知道的标准位置(这可能只是一个软链接),这对他们来说是最大的利益bash。更不用说,为什么hashbang不接受just #!bash并且使用PATH,而不是我们与完全相同env。我想,对于菜鸟还不够困惑。
ddekany

1
@JulioGuerra根据维基百科,您是真的:这不是“保证”。相反,它似乎“更有可能”。Wikipedia This mostly works because the path /usr/bin/env is commonly used for the env utility在这里说en.wikipedia.org/wiki/Shebang_(Unix)-我们必须信任env所有系统中“可能”存在的地方。
哈维·蒙特罗

2
@XaviMontero:我使用的系统env位于/bin,而不位于/usr/bin(不确定哪个可能是SunOS 4)中。这些天/usr/bin/env,由于#!/usr/bin/env黑客程序的普及,很有可能将其提供。
基思·汤普森

39

bash的标准位置是 /bin,我怀疑在所有系统上都是如此。但是,如果您不喜欢该版本的bash怎么办?例如,我想使用bash 4.2,但Mac上的bash为3.2.5。

我可以尝试重新安装bash,/bin但这可能不是一个好主意。如果我更新操作系统,它将被覆盖。

不过,我可以在中安装bash /usr/local/bin/bash并将PATH设置为:

PATH="/usr/local/bin:/bin:/usr/bin:$HOME/bin"

现在,如果我指定bash,我不会在那里得到旧的粗鲁的/bin/bash,而在那里会得到新的,更闪亮的/usr/local/bin。真好!

除了我的shell脚本有 !# /bin/bash爆炸。因此,当我运行shell脚本时,我得到的是bash的旧版本,它甚至没有关联数组。

使用/usr/bin/env bash将使用在我的PATH中找到的bash版本。如果我设置了PATH,那么/usr/local/bin/bash执行了它,那就是我的脚本将要使用的bash。

用bash很少见到这一点,但是在Perl和Python中它更为常见:

  • 某些专注于稳定性的 Unix / Linux版本有时会比这两种脚本语言的发布滞后。不久前,RHEL的Perl当时为5.8.8,这是Perl的八年版本!如果有人想使用更现代的功能,则必须安装自己的版本。
  • Perlbrew和Pythonbrew等程序可让您安装这些语言的多个版本。它们依赖于操纵PATH的脚本来获取所需的版本。对路径进行硬编码意味着我无法在brew下运行脚本。
  • 不久前(好吧,很久以前),Perl和Python并不是大多数Unix系统中包含的标准软件包。这意味着您不知道这两个程序的安装位置。在下面/bin吗?/usr/bin/opt/bin?谁知道?使用#! /usr/bin/env perl意味着我不必知道。

现在为什么不应该使用 #! /usr/bin/env bash

当在shebang中对路径进行硬编码时,我必须使用该解释器。因此,#! /bin/bash强迫我使用默认安装的bash版本。由于bash功能非常稳定(尝试在Python 3.x下运行2.x版本的Python脚本),我的特定BASH脚本不太可能无法正常工作,并且由于我的bash脚本可能已被该系统和其他系统使用,使用非标准版本的bash可能会产生不良影响。我很可能要确保shell脚本使用稳定的bash标准版本。因此,我可能想对我的shebang中的路径进行硬编码。


5
这是不正确的:“ bash的标准位置是/ bin,”(除非您可以引用标准文档),这可能更准确,因为它是大多数Linux发行版和macOS上的“常规”位置,但不是通常是unix系统上的标准(尤其不是大多数* bsds上的位置)。
tesch1

13

对于调用bash它有点过大。除非bash〜/ bin中有多个类似的二进制文件,否则这也意味着您的代码取决于$ PATH中包含正确的内容。

对于类似的事情,它很方便python。有包装脚本和环境导致替代python二进制文件。

但是,只要您确定它确实是您想要的二进制文件,使用二进制文件的确切路径就不会丢失任何内容。


当场python。我已经失去了多少地方的数量python可以发现😀
zigg

2
同意/usr/bin/env对Python更为有用,尤其是在使用virtualenv的情况下。
丹尼斯

10

/bin仅举几例,很多系统中没有Bash ,FreeBSD和OpenBSD。如果您打算将脚本移植到许多不同的Unices中,则可能要使用#!/usr/bin/env bash而不是#!/bin/bash

请注意,这不适用于sh;我专门使用Bourne兼容脚本#!/bin/sh,因为我认为现有的每个Unix几乎都包含sh在中/bin


在Ubuntu 18.04 /bindir中,我看到了sh -> dash。与象征性链接dash,揭示了Ubuntu的Debian性质。运行这三个命令字符串来实现这一切都归结到个人喜好:which bash然后which sh然后which dash
noobninja

0

我希望将主程序包装在下面的脚本中,以检查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 "$@"

0
 #!/usr/bin/env bash

绝对更好,因为它可以从系统环境变量中找到bash可执行文件路径。

转到您的Linux Shell并输入

env

它将打印所有环境变量。

转到您的shell脚本并输入

echo $BASH

它将打印您的bash路径(根据环境变量列表),您应使用该bash路径在脚本中构建正确的shebang路径。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.