通过/usr/bin/env运行一个命令的好处是可以在当前的环境中查找程序的默认版本。 这样,您就不必在系统的特定位置查找它,因为这些路径可能在不同系统的不同位置。只要它在您的路径中,它就会找到它。 一个缺点是不能传递多个参数(例如,您将无法编写/usr/bin/env awk -f),如果您希望支持Linux,则将该行解释为POSIX is vague,Linux将第一个空格后的所有内容解释为表示单个参数。您可以在某些版本的env上使用/usr/bin/env -S来解决此问题,但是这样的话,脚本的可移植性将变得更差,并且在相当新的系统上(例如,即使是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
#!/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
6条答案
按热度按时间kmbjn2e31#
通过
/usr/bin/env
运行一个命令的好处是可以在当前的环境中查找程序的默认版本。这样,您就不必在系统的特定位置查找它,因为这些路径可能在不同系统的不同位置。只要它在您的路径中,它就会找到它。
一个缺点是不能传递多个参数(例如,您将无法编写
/usr/bin/env awk -f
),如果您希望支持Linux,则将该行解释为POSIX is vague,Linux将第一个空格后的所有内容解释为表示单个参数。您可以在某些版本的env
上使用/usr/bin/env -S
来解决此问题,但是这样的话,脚本的可移植性将变得更差,并且在相当新的系统上(例如,即使是Ubuntu 16.04,如果不是更高版本的话)也会崩溃。另一个缺点是,由于您没有调用显式的可执行文件,因此可能会出现错误,并且在多用户系统上会出现安全问题(例如,如果有人设法在您的路径中获得了名为
bash
的可执行文件)。在某些情况下,第一种可能是首选的(比如用多个版本的python运行python脚本,而不必重新编写可执行代码),但在安全性是重点的情况下,后者可能是首选的,因为它限制了代码注入的可能性。
9lowa7mx2#
使用
#!/usr/bin/env NAME
可以使shell搜索$PATH环境变量中第一个匹配的NAME。如果你不知道绝对路径或者不想搜索它,这会很有用。nfg76nw03#
如果shell脚本以
#!/bin/bash
开头,它们将始终从/bin
开始以bash
运行。但是,如果它们以#!/usr/bin/env bash
开头,它们将在$PATH
中搜索bash
,然后从它们能找到的第一个开始。假设您要运行
bash
脚本,需要bash 4.x或更高版本,而您的系统只安装了bash
3.x,并且当前您的发行版没有提供更新的版本,或者您不是管理员,无法更改系统上安装的内容。当然,您可以下载bash源代码并从头构建自己的bash,例如将其放置到
~/bin
中。(PATH=$HOME/bin:$PATH
作为~
不会在$PATH
中展开).如果您现在调用bash
,shell将首先在$PATH
中按顺序查找它,因此它以~/bin
开头,如果脚本使用#!/usr/bin/env bash
搜索bash
,也会发生同样的事情,所以这些脚本现在可以使用您的自定义bash
构建在您的系统上工作。一个缺点是,这可能会导致意外的行为,例如,同一台机器上的同一脚本可能会使用不同的解释器运行,以用于不同的环境或具有不同搜索路径的用户,从而导致各种各样的麻烦。
env
最大的缺点是,某些系统只允许一个参数,因此您不能这样做#!/usr/bin/env <interpreter> <arg>
,因为系统将<interpreter> <arg>
视为一个自变量(它们将把它当作引用了该表达式),因此env
将搜索名为<interpreter> <arg>
的解释器。请注意,这不是env
命令本身的问题,它总是允许传递多个参数,但是系统的shebang解析器甚至在调用env
之前就解析这一行。同时,这个问题已经在大多数系统上得到了修复,但是如果你的脚本想要超便携,你不能相信这个问题已经在你将要运行的系统上得到了修复。它甚至可能会带来安全隐患,例如,如果
sudo
未配置为清理环境,或者$PATH
被排除在清理之外。通常
/bin
是一个受到很好保护的地方,只有root
可以在那里修改任何东西。但是你的home目录不是,你运行的任何程序都可以对它进行修改。这意味着恶意代码可能会把一个假的bash
放在某个隐藏的目录中,修改你的.bash_profile
以将该目录包含在你的$PATH
中,因此所有使用#!/usr/bin/env bash
的脚本最终都将使用伪bash
运行。例如,假设一个工具创建了一个包含以下内容的文件
~/.evil/bash
:让我们创建一个简单的脚本
sample.sh
:概念验证(在
sudo
保留$PATH
的系统上):通常,经典shell都应该位于
/bin
中,如果出于任何原因不想将它们放在那里,那么在/bin
中放置一个指向它们实际位置的符号链接确实不是问题(或者可能/bin
本身是符号链接),所以我总是使用#!/bin/sh
和#!/bin/bash
。如果它们不再工作,那么会有太多的东西被破坏。POSIX并不需要这些位置(POSIX没有标准化路径名,因此它甚至根本没有标准化shebang特性),但它们是如此普遍,即使一个系统不提供/bin/sh
,它可能仍然理解#!/bin/sh
,并知道如何使用它,可能只是为了与现有代码兼容。但是对于更现代的、非标准的、可选的解释器,如Perl、PHP、Python或Ruby,并没有真正指定它们应该位于哪里。(
/opt/...
,/Applications/...
,等等)。这就是为什么它们经常使用#!/usr/bin/env xxx
shebang语法的原因。s4chpxco4#
与
/usr/bin/bash/
中显式定义解释器的路径不同,通过使用env命令,可以从第一次找到解释器的位置搜索并启动解释器。jw5wzhpr5#
我发现它很有用,因为当我不知道env的时候,在我开始写脚本之前,我是这样做的:
然后我把文件中的那一行修改成了shebang。
我之所以这样做,是因为我不总是记得nodejs在我的计算机上的位置-- /usr/bin/或/bin/,所以对我来说
env
非常有用。piztneat6#
一个原因是它可以在Linux和BSD上移植。