是什么区别!“#在/ usr / bin中/ env的庆典”和“#!的/ usr /斌/庆典”?(W

2019-09-01 21:42发布

在的标头bash脚本,什么是这两个语句之间的区别?

  1. #!/usr/bin/env bash

  2. #!/usr/bin/bash

当我试图看到env手册页,我得到这样的定义:

 env - run a program in a modified environment

这是什么意思?

Answer 1:

通过运行一个命令/usr/bin/env有寻找任何程序的默认版本是在当前的ENV ironment利益。

这样一来,您不必寻找它在系统上的特定地方,这些路径可能在不同系统上的不同位置。 只要它是在你的路径,它会找到它。

一个缺点是,你将无法通过多个参数(例如,你将无法写/usr/bin/env awk -f )如果你想支持的Linux,因为POSIX是模糊的上线是如何成为解释和Linux第一空间后解释一切来表示一个参数。 您可以使用/usr/bin/env -S上的某些版本env来解决这个问题,但随后的脚本将变得更小便携,(如果没有后来如Ubuntu的甚至16.04)打破相当新的系统。

另一个缺点是,因为你没有调用一个明确的可执行文件,它有失误的可能性,并在多用户系统的安全问题(如果有人设法让他们的可执行文件,称为bash在你的路径,例如)。

#!/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脚本,而不必再处理可执行行)。 但在安全性是焦点的情况下,后者是优选的,因为它限制了代码注入的可能性。



Answer 2:

使用#!/usr/bin/env NAME ,使对名称的$ PATH环境变量中的第一个匹配的外壳搜索。 如果你不知道的绝对路径或不想寻找它,它可能是有用的。



Answer 3:

相反的明确定义为路径,以解释/usr/bin/bash/ ,使用env命令,解释的探索,不管它是第一个发现启动。 这既有上升空间和缺点



Answer 4:

我发现它是有用的,因为当我不知道ENV没有,之前我开始写剧本我这样做:

type nodejs > scriptname.js #or any other environment

然后我修改该文件到家当在该行。
我这样做,因为我并不总是记得是的NodeJS我的电脑-在/ usr / bin中/或/斌/,所以对我来说env是非常有用的。 也许有这个细节,但这是我的原因



Answer 5:

如果shell脚本下手#!/bin/bash ,他们将永远与运行bash/bin 。 如果他们然而,随着启动#!/usr/bin/env bash ,他们将寻找bash$PATH ,然后用他们能找到的第一个开始。

为什么会变成这样有用吗? 假设你想运行bash脚本,需要的bash 4.x或更新,但系统只bash安装3.x和目前你的版本没有提供一个较新的版本,或者您没有管理员,不能改变什么是安装在该系统。

当然,你可以下载bash的源代码,并从头开始建立自己的庆典,它放置到~/bin的例子。 而且你还可以修改您的$PATH在变量.bash_profile文件,包括~/bin的第一个条目( PATH=$HOME/bin:$PATH~不会扩大$PATH )。 如果你现在打电话bash ,shell将首先看看它在$PATH的顺序,因此它开始~/bin ,在那里您会发现您bash 。 同样的事情发生,如果脚本搜索bash使用#!/usr/bin/env bash ,所以这些脚本现在将您的系统上使用您的自定义工作bash版本。

一个缺点是,这可能会导致意外的行为,如在同一台机器可与不同的环境或用户提供不同的搜索路径不同的解释上运行相同的脚本,造成各种各样的麻烦。

与最大的缺点env是,有些系统将只允许一个参数,所以你不能做到这一点#!/usr/bin/env <interpreter> <arg>因为系统会看到<interpreter> <arg>作为一个参数(他们将其当作如果表达式被引述),因此env将搜索名为解释器<interpreter> <arg> 请注意,这不是一个问题, env命令本身,它总是允许多个参数,但通过与解析甚至称之前该行系统的家当解析器传递env 。 同时这已被固定在大多数系统上,但如果你的脚本想成为超便携,你不能依靠这已得到修复,你将运行在系统上。

它甚至可以带来安全隐患,例如,如果sudo没有配置清洁环境或$PATH从清理排除。 让我来证明这一点:

通常/bin是一个很好的保护的地方,只有root能够有任何改变。 你的主目录是没有,不过,你运行任何程序能够进行更改。 这意味着恶意代码可以放置假的bash到一些隐藏的目录下,修改你的.bash_profile ,包括你的那个目录$PATH ,因此使用的所有脚本#!/usr/bin/env bash将结束,假冒运行bash 。 如果sudo保持$PATH ,你有大麻烦了。

例如,考虑一个工具创建一个文件~/.evil/bash包含以下内容:

#!/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

#!/usr/bin/env bash

echo "Hello World"

概念(其中一个系统上的证明sudo保持$PATH ):

$ ./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 ,如果你不想在那里把他们无论出于何种原因,这真的不是放置在一个符号链接的问题/bin指向自己的真实位置(或者/bin本身是一个符号连接),所以我总是会一起去#!/bin/sh#!/bin/bash 。 这里还有太多,如果这些不再工作,将打破。 这并不是说POSIX需要这些位置(POSIX不规范的路径名,因此它甚至没有在所有规范家当功能),但他们是如此普遍,即使系统不会提供一个/bin/sh ,它很可能仍然了解#!/bin/sh ,并知道该怎么做它,可能它只是为与现有代码兼容。

但对于更现代的,非标准的,如Perl,PHP,Python和或Ruby解释器可选,它不是真正的地方指定他们应该位于何处。 他们可能是/usr/bin ,但他们可能也成为/usr/local/bin或在一个完全不同的层级分支( /opt/.../Applications/...等)。 这就是为什么这些经常使用#!/usr/bin/env xxx家当语法。



文章来源: What is the difference between “#!/usr/bin/env bash” and “#!/usr/bin/bash”?