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

时间:2014-02-06 20:09:30

标签: bash shebang

我在很多地方看到过,#!/usr/bin/env bash推荐使用#!/bin/bash而不是#!/usr/bin/env bash。我甚至看到过一个有进取心的个人What is the preferred Bash shebang?,这样做就会失去bash功能。

所有这一切,我在严格控制的测试环境中使用bash,其中每个循环驱动器基本上是单个主驱动器的克隆。我理解可移植性论点,虽然它不一定适用于我的情况。是否有任何其他理由更喜欢{{1}}替代方案,并且假设可移植性是一个问题,是否有任何理由使用它可能会破坏功能?

6 个答案:

答案 0 :(得分:174)

#!/usr/bin/envPATH搜索bashbash并非始终在/bin,特别是在非Linux系统上。例如,在我的OpenBSD系统上,它位于/usr/local/bin,因为它是作为可选包安装​​的。

如果你完全确定bash/bin并且永远都是,那么将它直接放在你的垃圾中是没有害处的 - 但我建议不要这样做,因为脚本和程序都有生命超出我们最初认为他们将拥有的。

答案 1 :(得分:30)

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

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

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

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

现在,如果我指定bash,我不会在/bin/bash获得旧的,而在/usr/local/bin更新的更狡猾的。尼斯!

除了我的shell脚本有!# /bin/bash shebang。因此,当我运行我的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可能会产生不良影响。我很可能想确保bash的稳定标准版本与我的shell脚本一起使用。因此,我可能想在我的shebang中硬编码路径。

答案 2 :(得分:11)

要调用bash,这有点过分。除非您在〜/ bin中有多个bash二进制文件,但这也意味着您的代码依赖于$ PATH,其中包含正确的内容。

虽然像python这样的东西很方便。有包装脚本和环境导致使用替代的python二进制文件。

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

答案 3 :(得分:10)

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

请注意,这不适用于sh;对于符合Bourne的脚本,我专门使用#!/bin/sh,因为我认为现有的每个Unix在sh中都有/bin

答案 4 :(得分:0)

# Iterating over new dataframe
for i, element in enumerate(new["date"]):

    # Finding corresponding date in original
    result = original[original.eq(element.date()).any(1)]

    # coefficient and intercept value from original table
    # for particular datetime value from new table
    c, i_ = result["coefficient"], result["intercept"]
    col1v = new.iloc[i:i+1]["col1"]

    # Adding result of multiplication into another column
    new["result"].iloc[i:i+1] = np.add(np.multiply(col1v, c), i_)

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

转到您的Linux shell并键入

 #!/usr/bin/env bash

它将打印您的所有环境变量。

转到您的shell脚本并键入

env

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

答案 5 :(得分: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 "$@"