#!/bin/bash 和 #!/usr/bin/env bash 的区别_十甫寸木南的博客-程序员秘密_#!/usr/bin/env bash

技术标签: Shell  shell  

起因

为什么会想到写 #!/bin/bash#!/usr/bin/env bash 的区别呢?还要从一次装插件的过程说起。
由于刚开始接触 Shell Script 不久,对一些语法用法等还不是很熟悉,所以,当时在 IDE 上装了一些 Shell 的插件,包括 Shellcheck、Shell Process、BashSupport 等一大堆。然后呢,我的 IDE 就多了很多之前没有的功能,于是,满怀激动的我准备尝试一下。
新建一个 Shell 脚本 -> 写 Shebang、 咦?
在写 Shebang 的时候出现了一个奇怪的事,如下图:
Shebang hint
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 程序所在的位置,如下:️
bash place
而有了命令解释器的位置声明,那么,当执行该脚本时,系统就知道该去哪里找这个命令解释器,也就是 Shebang 中指定的 bash 。

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

#!/usr/bin/env bash

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

  1. 首先,来看一下命令 env 的位置
    env place
    也就是说,#!/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
    可以看到,在 $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/python与#!/usr/bin/env python的区别 的作者认为,应该优先使用 #!/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
  • 看自己的意愿,喜好

参考资料

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37164975/article/details/106181500

智能推荐

C语言编程>第六周 ① 编写一个录入函数:用来从键盘接收n个整型数并存放在一个整型数组中。 在主函数中调用该函数计算出这n个整数之和。_编写函数用来计算如下公式的值。输入整数n,调用该函数,求出s的值,要求保留2位_朽木自雕i的博客-程序员秘密

例题:编写一个录入函数:用来从键盘接收n个整型数并存放在一个整型数组中。在主函数中调用该函数计算出这n个整数之和。代码如下:/*代码分析:录入函数需要两个参数:一个参数是需要用来存储数字的数组,另一个参数是录入数的总数*/#include <stdio.h>void pengwei_sun(int a[],int n);//定义一个输入数组的元素int main(){ int n,i,b[100],sum=0; printf("输入你想相加多少数:");//提示信息 scan

A taste of Chengdu_EllieArm1996的博客-程序员秘密

Here I am in Chengdu, at the end of my eleventh full day in China!! I’m in my dorm as I write this, East International Student Dormitory; we moved here last Saturday after spending our first night in

sklearn.metrics.classification_report_每天进步一点点2017的博客-程序员秘密

分类报告:sklearn.metrics.classification_report(y_true, y_pred, labels=None, target_names=None,sample_weight=None, digits=2),显示主要的分类指标,返回每个类标签的精确、召回率及F1值主要参数说明:labels:分类报告中显示的类标签的索引列表target_names:显

android 布局属性(alignBaseLine在最后有详细解释)_layout_alignbaseline_瑾兰的博客-程序员秘密

android 布局属性(alignBaseLine在最后有详细解释)重点内容android:id 为控件指定相应的ID android:text 指定控件的文本,置尽量使用strings.xml android:grivity 指定控件的基本位置 ,比如举重,居右, android:padding 指定控件的内边距,控件当中的内容 android:singleLine 如果设置为真的话,则

centos 及windows ntp 时间同步实践_卧似昭昂的博客-程序员秘密

今天发现北斗传输数据失败,是时间的问题,解决方法如下:centos: ntpdate 1.cn.pool.ntp.org     先进行对时              hwclock -w 更新bios时间              vi /etc/crontab   添加30 21 * * * root /usr/sbin/ntpdate cn.pool.ntp.org && /sb

python中的变量,赋值等详细解析_python变量第一次赋值和第二次赋值的地址区别_L-Lawliet-的博客-程序员秘密

在 python 中赋值语句总是建立对象的引用值,而不是复制对象。因此,python 变量更像是指针,而不是数据存储区域,这点和大多数 OO 语言类似吧,比如 C++、java 等 ~1、先来看个问题吧:在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?>>> values = [0, 1, 2]>&gt...

随便推点

有过一个胖妞_ycdyx的博客-程序员秘密

更多:http://www.webyang.net/Html/web/article_142.html之前工作的时候,公司里有个胖妞,和我是搭档。 她是做页面设计的,也切图,也写CSS+DIV,其实也算前端了。公司是个大公司来着,美女如云,但只要好事者通过多方打听,基本上会发现都已经名花有主。还是看近一点的吧,胖妞是单身。胖妞其实也不是很胖,用她自己的话讲,叫虚胖,都是水来着。她比

全球最贵域名Sex.com将再度出售_sex网站_vacuum_tube的博客-程序员秘密

<br />金融时报消息称,Sex.com域名曾位居全球最贵域名前例,四年前,它以1400万美元成交,不过,买下此域名的公司面临破产,因此Sex.com将再度拿来出售。<br />  Sex.com域名的拥有者为EscomLLC,它是一家洛杉基公司,2006年时它贷款买下此域名,不过却无法偿还贷款。本来,由于丧失抵押品赎回权,域名连同网站将在今年3月拍卖,但债权人觉得这笔资产能获得列高的价格。因此,域名将由德国域名管理公司Sedo拿来出售,该公司称已经有数个买家有兴趣购买。<br />  4年前

1 线性表_blackboydec的博客-程序员秘密

1 抽象数据类型理解抽象数据类型 我们对已有的数据类型进行抽象,就有了抽象数据类型。抽象数据类型(Abstract Data Type,ADT)是指一个数学模型及定义在该模型上的一组操作。抽象数据类型的定义仅取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关。比如1+1=2这样一个操作,在不同CPU的处理上可能不一样,但由于其定义的数学特性相同,所以在计算机编程者看来,它们都是相

Azure上找不到MongoDB?不妨试试Azure Cosmos DB_azura mongodb_江湖人称于老师的博客-程序员秘密

最近被问到Azure上的MongoDB在哪里?答:Azure上目前没有Paas层的Mongo DB可用,但仍有两种方式使用Mongo DB, 1是使用Iaas层的虚拟机构建MongoDB集群,2.是使用更强大的Paas层的Cosmos DB。Azure Cosmos DB是多区域分布式多模型数据库服务。您可以观看以下视频内容了解Azure Cosmos DB或者跳过...

使用DatePicker和TimePicker设置日期和时间_datepicker 日期加时间_qqazl001的博客-程序员秘密

此文,仅做为个人学习Android,记录成长以及方便复习!首先是设置UI界面(有点丑)1.activity_main.xml&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&amp;lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; android:lay...

当C++遇到空指针异常......_c++空指针异常怎么解决_柴郡猫乐园的博客-程序员秘密

在Java语言中,有空指针异常,在编程时为了代码安全,在遇到空指针时,防止程序崩溃,会捕捉空指针异常,即NullPointerException异常类。比如下面就是一段捕获NullPointerException异常的Java代码片段:try { 。。。。} catch (NullPointerException e) { e.printStackTrace();}当try语句块中的代码访问到空指针后,会抛出NullPointerException,随后在catch语句捕获这个异常,并

推荐文章

热门文章

相关标签