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

我曾经在很多地方看到过,包括对这个网站的推荐( 什么是首选Bash shebang? ),使用#!/usr/bin/env bash优先于#!/bin/bash 。 我甚至看到一个有进取心的人build议使用#!/bin/bash错误的,而bash的function会因此丢失。

所有这一切,我使用bash在一个严格控制的testing环境中,每个stream通驱动器基本上是一个主驱动器的克隆。 我理解可移植性的论点,虽然它不一定适用于我的情况。 有没有其他的理由更喜欢#!/usr/bin/env bash的替代品,并假设便携性是一个问题,是否有任何理由使用它可能会破坏function?

#!/usr/bin/envbashsearchPATHbash并不总是在/bin ,特别是在非Linux系统上。 例如,在我的OpenBSD系统上,它位于/usr/local/bin ,因为它是作为可选包安装​​的。

如果你完全确定bash是在/bin并且永远是这样的,那么将它直接放在你的文件中是没有什么坏处的,但是我build议不要这样做,因为脚本和程序都超出了我们最初相信的程度。

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

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

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

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

现在,如果我指定了bash ,我不会在/bin/bash得到旧的cruddy,而是在/usr/local/bin更新,更炫的。 太好了!

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

使用/usr/bin/env bash将使用在我的PATH中find的bash版本。 如果我设置我的path,以便执行/usr/local/bin/bash ,那是我的脚本将使用的bash。

用bash来看这是很less见的,但在Perl和Python中更常见:

  • 某些专注于稳定性的 Unix / Linux版本有时候会随着这两种脚本语言的发布而落后。 不久前,RHEL的Perl版本是5.8.8 – 一个八年的Perl版本! 如果有人想要使用更多的现代function,你必须安装自己的版本。
  • 像Perlbrew和Pythonbrew这样的程序允许你安装这些语言的多个版本。 他们依靠脚本来操纵你的PATH来获得你想要的版本。 硬编码path意味着我不能在brew下运行我的脚本。
  • 不久之前(好吧,很久以前)Perl和Python不是大多数Unix系统中包含的标准软件包。 这意味着你不知道这两个程序的安装位置。 在/bin吗? /usr/bin/opt/bin ? 谁知道? 使用#! /usr/bin/env perl #! /usr/bin/env perl意味着我不必知道。

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

当path在shebang中硬编码时,我必须和解释器一起运行。 因此, #! /bin/bash #! /bin/bash强制我使用默认的安装版本的bash。 由于bash特性非常稳定(尝试在Python 3.x下运行Python脚本的2.x版本),所以我的特定BASH脚本不太可能工作,因为我的bash脚本可能被这个系统和其他系统,使用非标准版本的bash可能会产生不良影响。 这很可能是我想确保稳定的标准版本的bash与我的shell脚本一起使用。 因此,我可能想要硬编码我的shebangpath。

为了调用bash这有点矫枉过正。 除非你有〜/ bin中的多个bash二进制文件,但是这也意味着你的代码依赖于$ PATH,并且有正确的东西。

对于像python这样的东西来说,它是非常方便的。 有包装脚本和环境,导致使用替代python二进制文件。

但是,只要您确定它是您真正想要的二进制文件,就不会使用二进制文件的确切path。

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

请注意,这不适用于sh ; 对于Bourne兼容的脚本,我完全使用#!/bin/sh ,因为我认为现有的每个Unix都已经在/bin