关于linux:“#!/usr/bin/env bash” 和“#!/usr/bin/bash”有什么区别?

What is the difference between “#!/usr/bin/env bash” and “#!/usr/bin/bash”?

bash脚本的头部分,这两个语句有什么区别?

  • #!/usr/bin/env bash

  • #!/usr/bin/bash

  • 当我试图看到env手册页时,我得到了以下定义:

    1
     env - run a program in a modified environment

    这是什么意思?


    通过/usr/bin/env运行命令有助于查找当前环境中程序的默认版本。

    这样,您就不必在系统上的特定位置查找它,因为这些路径可能位于不同系统上的不同位置。只要它在你的道路上,它就会找到它。

    一个缺点是,如果您希望支持Linux,您将无法传递多个参数(例如,您将无法写入/usr/bin/env awk -f),因为posix对行的解释方式很模糊,Linux解释第一个空格后的所有内容以表示单个参数。您可以在某些版本的env上使用/usr/bin/env -S来解决这个问题,但是脚本将变得更不可移植,并在相当新的系统上中断(例如,如果不是更晚的话,甚至Ubuntu 16.04)。

    另一个缺点是,由于您没有调用显式可执行文件,因此它有可能出错,并且在多用户系统安全问题上(例如,如果有人设法在您的路径中获得其可执行文件bash)。

    1
    2
    #!/usr/bin/env bash #lends you some flexibility on different systems
    #!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

    在某些情况下,第一个脚本可能是首选的(比如使用多个版本的python运行python脚本,而不必重新编写可执行行)。但在以安全性为重点的情况下,后者是首选的,因为它限制了代码注入的可能性。


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


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


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

    1
    type nodejs > scriptname.js #or any other environment

    然后我把文件中的那一行修改为shebang。我这样做是因为我不记得nodejs在我的电脑上的位置--/usr/bin/或/bin/,所以对我来说env非常有用。也许有细节,但这是我的原因


    如果壳牌剧本以#!/bin/bash开始,它们将永远与bash一起运行。如果他们仍然以#!/usr/bin/env bash开始,他们将在$PATH开始寻找,然后第一个可以找到。

    为什么这会很有用?如果你想运行的脚本,需要Bash 4.X或Newer,你的系统只有bash〔1〕3.X安装,目前的分布并不提供一个新的版本,或者你是一个管理者,无法改变系统上安装的内容。

    在课程中,您可以下载源代码,并从脚本中建立自己的基础,以~/bin为例。你也可以修改你的$PATH变量,1〔10〕File to include ~/bin作为第一个入口(PATH=$HOME/bin:$PATH作为EDOCX1〕〔13〕不会扩展到$PATH。如果你现在叫bash,壳牌将首先在$PATH上看着它,所以它将以~/bin开始,它将在哪里找到你的bash。同样的情况,如果用#!/usr/bin/env bash搜索脚本,那么这些脚本现在将使用您的自定义bash在您的系统上工作。

    One downside is,that this can lead to unexpected behavior,E.G.same script on the same machine may run with different interpreters for different environments or users with different search paths,causing all kind of headaches.

    有一些系统只允许一个论据,所以你不能这样做,因为系统会看到EDOCX1[…]24],作为一个论据(他们会把它当作表达式的一部分)和Thus EDOCX1[…]22],将搜索一个翻译名称EDOCX1[…]24]。注意到这不是envCommand ITSELF的问题,ITSELF always allowed multiple parameters to be passed through,but with the Shebang Parser of the system that Parses this line before even calling env意思是,当这个已经固定在最基本的系统上,但如果你的脚本想要超便携,你不能认为这个已经固定在系统上,你会跑步。

    它甚至可能产生安全影响,E.G.If sudowas not figured to clean environment or $PATHwas excluded from clean up.让我看看

    通常,这是一个很好的保护场所,只有它能改变任何东西。你的家庭目录不是,尽管,你运行的任何程序都可以改变它。这意味着聪明的代码可以将一个伪造的bash〔1〕转换成隐藏的目录,修改.bash_profile包括在你的$PATH中的这个目录,所以所有的脚本都会使用#!/usr/bin/env bash结束与这个伪造的EDOCX1〕一起运行。如果你有麻烦的话,请继续。

    E.G.Consider a tool creates a file ~/.evil/bashwith the following content:

    1
    2
    3
    4
    5
    6
    7
    8
    #!/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

    ZZU1

    Proof of concept(on a system where EDOCX1&29).Keeps EDOCX1&5):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ ./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

    通常,经典壳牌应该放在/bin中,如果你不想把它们放在那里,无论原因为何,这并不是一个真正的问题,也不是一个将SYMLINK放在/bin的问题。如果他们不工作,那就太多了。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 a t all)but they're so common,even if a system would not offer a /bin/sh,it could still understand #!/bin/shand know what to do with it and may be conversability for itITH Existing Code.

    但对于更现代的、非标准的、选择性的解释者,比如珍珠、PHP、Python或红宝石,这并不是真的具体说明他们应在何处定位。他们可能在/usr/bin但他们可能在/usr/local/bin或完全不同的等级分支机构(/opt/.../Applications/...等)。这就是为什么他们经常使用#!/usr/bin/env xxxShebang Syntax。