“#!/usr/bin/env bash”和“#!/usr/bin/bash”有什么区别?
- 2024-10-18 09:00:00
- admin 原创
- 86
问题描述:
在 Bash 脚本的头部中,这两个语句有什么区别:
#!/usr/bin/env bash
#!/usr/bin/bash
当我查阅env
手册页时,我得到了这个定义:
env - run a program in a modified environment
这是什么意思?
解决方案 1:
运行命令/usr/bin/env
的好处是可以查找当前环境中该程序的默认版本。
这样,您就不必在系统的特定位置寻找它,因为这些路径可能在不同系统上位于不同位置。只要它在您的路径中,它就会找到它。
/usr/bin/env awk -f
一个缺点是,如果您希望支持 Linux,您将无法传递多个参数(例如,您将无法写入),因为 POSIX对于如何解释该行含糊其辞/usr/bin/env -S
,而 Linux 会将第一个空格后的所有内容解释为表示单个参数。您可以在某些版本上使用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 脚本,而不必重新编写可执行行)。但在以安全性为重点的情况下,后者将是首选,因为它限制了代码注入的可能性。
解决方案 2:
使用#!/usr/bin/env NAME
使 shell 在 $PATH 环境变量中搜索 NAME 的第一个匹配项。如果您不知道绝对路径或不想搜索它,它会很有用。
解决方案 3:
如果 shell 脚本以 开头,它们将始终以from#!/bin/bash
运行。但如果它们以 开头,它们将搜索in ,然后从找到的第一个开始运行。bash
`/bin#!/usr/bin/env bash
bash`$PATH
为什么这很有用?假设您要运行bash
需要 bash 4.x 或更新版本的脚本,但您的系统只bash
安装了 3.x,并且当前发行版不提供更新版本,或者您不是管理员,无法更改该系统上安装的内容。
当然,您可以下载 bash 源代码并从头开始构建自己的 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
,它总是允许传递多个参数,但系统的 shebang 解析器会在调用之前解析此行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
通常,经典的 shell 都应该位于 中/bin
,如果您出于某种原因不想将它们放在那里,那么在 中放置一个/bin
指向它们真实位置的符号链接(或者/bin
它本身就是一个符号链接)真的不是问题,所以我总是选择 和#!/bin/sh
。#!/bin/bash
如果这些不再起作用,那么会有很多问题。并不是 POSIX 需要这些位置(POSIX 不标准化路径名,因此它甚至根本不标准化 shebang 功能)但它们非常常见,即使系统不提供/bin/sh
,它可能仍然会理解#!/bin/sh
并知道如何处理它,并且可能只是为了与现有代码兼容。
但对于更现代、非标准、可选的解释器(如 Perl、PHP、Python 或 Ruby),实际上并没有指定它们应该位于何处。它们可能位于/usr/bin
,但也可能位于/usr/local/bin
完全不同的层次结构分支中(/opt/...
、/Applications/...
等)。这就是为什么它们经常使用#!/usr/bin/env xxx
shebang 语法。
解决方案 4:
通过使用 env 命令,无需像 中那样明确定义解释器的路径/usr/bin/bash/
,而是从首次找到解释器的位置搜索并启动解释器。这既有优点也有缺点
解决方案 5:
我发现它很有用,因为当我不知道 env 时,在我开始编写脚本之前我正在这样做:
type nodejs > scriptname.js #or any other environment
然后我将文件中的该行修改为 shebang。
我这样做是因为我总是记不住计算机上的 nodejs 在哪里——/usr/bin/ 或 /bin/,所以对我来说env
这非常有用。也许这方面还有细节,但这就是我的理由
解决方案 6:
一个原因是它可以在 Linux 和 BSD 之间移植。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件