Contents

#!/usr/bin/bash和#!/usr/bin/env bash的区别

1. 概述

Shebang 是一个由井号和感叹号 ( #! ) 组成的字符序列。在 Linux、Solaris、macOS、BSD 和其他基于 Unix 的系统中,它通常用作脚本文件的第一行,以指定执行文件中存在的命令的解释器。

在本教程中,我们将找出*#!/usr/bin/bash#!/usr/bin/env bash*之间的区别。此外,我们将讨论它们的优缺点。

2. 设置

使用像nano 这样的文本编辑器,让我们创建并打开一个可执行文件sample.sh

$ nano sample.sh

然后,我们将此内容添加到文件中:

#!/usr/bin/bash
echo "Blogdemo is Awesome!"

我们还需要使用chmod命令使脚本文件可执行:

$ chmod u+x sample.sh

在这里,u+x标志授予对当前用户 ( u )的执行( x )访问权限。

我们将在本教程中使用此文件来测试*#!/usr/bin/bash#!/usr/bin/env bash*行的行为。

3. 使用*#!/usr/bin/bash*

** #!/usr/bin/bash是脚本文件中使用的一个解释行,用于将位于“/bin”目录中的bash设置为执行文件中存在的命令的默认 shell。**

它定义了 Bash shell的绝对路径*/usr/bin/bash* 。这通常是几乎所有基于 Unix 的操作系统中 Bash shell 的默认位置。

要找出 Bash 在我们系统中的位置,我们可以使用which 命令:

$ which bash
/usr/bin/bash

由于我们创建的sample.sh已经包含了这个解释行,让我们运行它:

$ ./sample.sh
Blogdemo is Awesome!

我们还可以使用*#!/usr/bin/bash* shebang 行将额外的参数传递给 shell 解释器:

#!/usr/bin/bash -r

该解释行用于使用 Bash 解释器执行命令。-r选项启用受限 shell 模式。

当我们想要准确地指向解释器的绝对路径时,建议使用*#!/usr/bin/bash*解释行。它也有比较高的安全性,我们可以传递额外的参数。

**不利的一面是,它的可移植性很差,因为不同的系统可以在不同的位置安装解释器。**也很难记住所有解释器的绝对路径,尤其是在安装了多个解释器的系统中,包括pythonzshcshkshsh 和tcsh

4. 使用*#!/usr/bin/env bash*

正如我们前面提到的,** #!/usr/bin/env bash也是脚本文件中用于使用 Bash shell 执行命令的解释行。**

它使用env 命令显示系统中存在的环境变量,然后使用定义的解释器执行命令。

env命令通过指示系统通过$PATH 变量查找指定的解释器并使用找到的第一个匹配项来工作。它位于基于 Unix 的系统中的*“/usr/bin/env”* 目录中。

我们可以使用which命令验证它在我们系统上的位置:

$ which env
/usr/bin/env

让我们使用env来显示当前由 shell 定义的所有环境变量:

$ env
SHELL=/bin/bash
SESSION_MANAGER=local/user-PC:@/tmp/.ICE-unix/2839,unix/user-HP-Pavilion-g6-Notebook-PC:/tmp/.ICE-unix/2839
QT_ACCESSIBILITY=1
COLORTERM=truecolor
...truncated

接下来,让我们使用grep 从env命令中显示*$PATH* :

$ env | grep PATH
WINDOWPATH=2
PATH=/home/username/.rbenv/shims:/home/username/.rbenv/bin:/home/username/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

从上面的输出中,我们可以看到*$PATH包含指向/bin*和其他目录的符号链接,用冒号分隔。

为了测试这个解释行,我们先修改sample.sh文件的第一行:

#!/usr/bin/env bash

然后,我们可以执行脚本文件:

$ ./sample.sh
Blogdemo is Awesome!

*通过/usr/bin/env*运行脚本文件的好处是可以在当前环境中自动搜索默认版本的解释器。**这样,我们不需要在系统中的特定位置搜索它,因为在其他系统中路径可能不同。

我们还可以指定要使用的解释器版本。下面是指定 Bash 解释器版本的示例格式:

#!/usr/bin/env bashX.x

#!/usr/bin/env bash 解释行提供了更多的可移植性,因为我们不必编写解释器的绝对路径。

但是,它不支持多个参数。这是因为声明的解释器及其选项被解析为一个参数。

此外,在我们的环境中有多个版本的解释器的情况下,它可能容易出错,因为它使用*$PATH中找到的第一个bash*实例。

5. 比较

下表显示了这些 shebang 行之间的比较:

#!/usr/bin/bash #!/usr/bin/env bash
提供更多安全性 提供更多的便携性
更具体地说,因为我们必须声明解释器的确切路径 自动搜索环境中第一次出现的解释器
可以支持解释器声明后传递的额外参数 无法支持额外参数,因为系统将它们作为单个命令读取