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

简介: Linux - #!/bin/bash 和 #!/usr/bin/env bash 的区别

起因

为什么会想到写 #!/bin/bash 和 #!/usr/bin/env bash 的区别呢?还要从一次装插件的过程说起。
由于刚开始接触 Shell Script 不久,对一些语法用法等还不是很熟悉,所以,当时在 IDE 上装了一些 Shell 的插件,包括 Shellcheck、Shell Process、BashSupport 等一大堆。然后呢,我的 IDE 就多了很多之前没有的功能,于是,满怀激动的我准备尝试一下。

新建一个 Shell 脚本 -> 写 Shebang、 咦?

在写 Shebang 的时候出现了一个奇怪的事,如下图:

IDE 居然给我提示了这么多!

zsh、bash、csh、ksh 这些解释器虽然有些我没用过,但是我知道它们的含义。可是,在我的印象里,Shell 脚本的 Shebang 不是应该这样写吗(以前的认知)?⬇️

#!/bin/bash or #!/bin/sh

为什么 IDE 给我的提示是这样的➡️:#!/usr/bin/env bash

这是个什么写法?我有点疑惑。

但是,虽然很疑惑,可是我当时并没有深究,而是开始试验我新装的插件了,于是,这个疑惑被压箱底了。

再次看到这个问题呢,是前几天在公众号上看到一个文章,对这个问题做出了解释,至此,我才恍然大悟。

而今天,刚好无事,也就想着把这个问题记录一下。

区别

#!/bin/bash

对于 #!/bin/bash 呢,我想大多数写过脚本的应该都知道,这是一个命令解释器的声明,通常位于脚本的第一行,同时,该行还有个专业的名字,叫做 Shebang 。(不知道 Shebang 的可以去查一下)

作为对命令解释器的声明,#!/bin/bash 声明了 bash 程序所在的位置,如下:⬇️

而有了命令解释器的位置声明,那么,当执行该脚本时,系统就知道该去哪里找这个命令解释器,也就是 Shebang 中指定的 bash 。

同理,#!/bin/sh 也是一样的,包括非 Shell 脚本,如 #!/usr/bin/python 也是同理,都是声明命令解释器的位置。

#!/usr/bin/env bash

对于 #!/usr/bin/env bash ,说实话,刚开始我真不知道这是个什么写法,关键是我之前没见过。
而在看了一篇文章后,我总算是弄明白了,具体如下:⬇️

1、首先,来看一下命令 env 的位置

也就是说,#!/usr/bin/env bash 确实是使用了 env 命令做了一些事!

但是,在我通常的用法中,我使用 env 都是用来查看一些环境变量的啊!难道说,env 命令还有别的用法?

2、查看一下 env 命令的定义及用法

我常用的一个 Linux 命令网站上对 env 是这么解释的:

env 命令用于显示系统中已存在的环境变量,以及在定义的环境中执行指令

那也就是说,env 命令后面确实可以接一些指令!

那么,bash 就是这个所谓的指令?

可是,#!/bin/bash 声明了 bash 所在位置,所以系统知道该去哪里找 bash !

那 #!/usr/bin/env bash 呢?该语句只声明了 env 的所在位置,并没有声明 bash 的位置啊,那系统去哪里找 bash 呢?

3、原来,系统是去 $PATH 里找 bash 的位置了!

当你执行 env python 时,它其实会去 env | grep PATH 里(也就是 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin)这几个路径里去依次查找名为 python 的可执行文件。

那么,我们来看一下 $PATH 吧:⬇️

可以看到,在 $PATH 的内容中有很多的目录位置,而其中,bash 所在的 /bin 赫然在列!

所以说,#!/usr/bin/env bash 就是在 $PATH 中挨个目录依次去找 bash 的

看到这里,对于 #!/usr/bin/env bash 我就彻底搞明白了。也就是说:⬇️

  • #!/bin/bash 是直接指定了应该去哪里找 bash
  • #!/usr/bin/env bash 则是告诉系统去 $PATH 包含的目录中挨个去找吧,先找到哪个,就用哪个

#!/bin/bash 和 #!/usr/bin/env bash 到底该用哪个

一文章作者说应该优先使用 #!/usr/bin/env bash 这种写法!

这两个问答可以说写的非常全面,不仅解释了 #!/bin/bash 和 #!/usr/bin/env bash 的区别,还同时说明了应该在何种场景下使用哪种写法,并详细阐述了其原因。

下面,就对这两篇问答中提到的内容及原因做一些说明:

#!/usr/bin/env bash 的优缺点

  • 优点

    • #!/usr/bin/env bash 不必在系统的特定位置查找命令解释器,为多系统间的移植提供了极大的灵活性和便利性(某些系统的一些命令解释器并不在 /bin 或 一些约定的目录下,而是一些比较奇怪的目录)
    • 在不了解主机的环境时,#!/usr/bin/env bash 写法可以使开发工作快速地展开
  • 缺点

    • #!/usr/bin/env bash 在对安全性比较看重时,该写法会出现安全隐患

      #!/usr/bin/env bash 从 $PATH 中查找命令解释器所在的位置并匹配第一个找到的位置,这意味着可以伪造一个假的命令解释器(如自己写一个假的 bash),并将伪造后的命令解释器所在目录写入 PATH 环境变量中并位于靠前位置,这样,就形成了安全隐患

      而 /bin 由于一般只有 root 用户才有操作权限,所以,#!/bin/bash 这种写法相对较为安全

    • #!/usr/bin/env 无法传递多个参数(这是由于 Shebang 解析造成的,并非 env 命令的缘故)

      如:
      #!/usr/bin/perl -w
      #!/bin/csh -f
      而如果使用 #!/usr/bin/env perl -w 这种写法的话,perl -w 会被当成一个参数,于是,根本找不到 perl -w 这个命令解释器,就会出错

    • 某些系统 env 命令的位置也比较奇怪,这种写法会找不到 env 命令

#!/bin/bash 的优缺点

  • 优点

    • 准确指出所需命令解释器的位置
    • 安全性相对较高
    • 可以传递多个参数
  • 缺点

    • 移植性相对较差,很多系统的命令解释器位置不一致
    • 一些命令解释器的位置记不住

到底用哪个

  • 两个都可以
  • 如果对安全性比较看重,使用 #!/bin/bash
  • 如果对安全性不是很看重,但对移植性(灵活性)比较看重,使用 #!/usr/bin/env bash
  • 看自己的意愿,喜好
目录
相关文章
|
4月前
|
存储 Ubuntu 安全
Linux中Centos和Ubuntu的区别
CentOS主要面向服务器环境,而Ubuntu适用于服务器和桌面环境。   CentOS提供更精简的安装,而Ubuntu提供更广泛的开箱即用功能。   CentOS遵循RHEL的所有安全实践,而Ubuntu在安全方面采取更积极的方法。
|
4月前
|
Ubuntu 安全 Unix
Linux和Ubuntu有什么区别
综上所述,Linux和Ubuntu之间存在明显的区别。Linux是一种操作系统内核,而Ubuntu是基于Linux内核的发行版本,具有更好的易用性、社区支持和软件仓库。用户可以根据自己的需求选择不同的Linux发行版本,如果需要一个稳定、易于使用的桌面环境,Ubuntu是一个不错的选择。如果需要更加灵活和定制性强的系统,其他Linux发行版本可能更加适合。
|
5月前
|
安全 Unix Java
linux中kill -9和kill -15区别
在 Linux/Unix 系统中,`kill -9` 和 `kill -15` 是终止进程的常用命令,核心区别在于发送的信号类型不同,导致进程终止行为截然不同。`kill -15`(SIGTERM)允许进程进行清理操作后优雅退出,适用于正常关闭;而 `kill -9`(SIGKILL)则强制终止进程,不给予任何清理机会,仅在进程无响应时使用。本文从信号类型、行为、工作原理及使用建议等方面进行详细对比,帮助你更安全、有效地管理进程。
687 0
|
9月前
|
Unix Linux 编译器
windows下和linux下cmake的规则有区别吗
通过合理使用CMake的条件逻辑和平台特定的配置选项,开发者可以编写更加灵活和健壮的CMake脚本,确保项目在Windows和Linux上的一致性和可移植性。
465 76
|
10月前
|
Linux
linux syscall和int 80的区别
通过以上内容,希望您能更清晰地理解 `int 0x80` 和 `syscall` 的区别及其在不同系统架构中的应用。
690 99
|
10月前
|
缓存 Ubuntu Linux
Linux中yum、rpm、apt-get、wget的区别,yum、rpm、apt-get常用命令,CentOS、Ubuntu中安装wget
通过本文,我们详细了解了 `yum`、`rpm`、`apt-get`和 `wget`的区别、常用命令以及在CentOS和Ubuntu中安装 `wget`的方法。`yum`和 `apt-get`是高层次的包管理器,分别用于RPM系和Debian系发行版,能够自动解决依赖问题;而 `rpm`是低层次的包管理工具,适合处理单个包;`wget`则是一个功能强大的下载工具,适用于各种下载任务。在实际使用中,根据系统类型和任务需求选择合适的工具,可以大大提高工作效率和系统管理的便利性。
1166 25
|
12月前
|
Linux Android开发 开发者
linux m、mm、mmm函数和make的区别
通过理解和合理使用这些命令,可以更高效地进行项目构建和管理,特别是在复杂的 Android 开发环境中。
636 18
|
3月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
475 1
二、Linux文本处理与文件操作核心命令
|
3月前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
325 137
|
3月前
|
安全 Ubuntu Unix
一、初识 Linux 与基本命令
玩转Linux命令行,就像探索一座新城市。首先要熟悉它的“地图”,也就是/根目录下/etc(放配置)、/home(住家)这些核心区域。然后掌握几个“生存口令”:用ls看周围,cd去别处,mkdir建新房,cp/mv搬东西,再用cat或tail看文件内容。最后,别忘了随时按Tab键,它能帮你自动补全命令和路径,是提高效率的第一神器。
760 57