哈喽大家好,我是咸鱼

不知道小伙伴们在写 Bash 脚本或者说看别人的 Bash 脚本的时候有没有注意过脚本的第一行

#!/bin/bash

Bash 脚本的第一行往往以 #! 开头,这一行称作 shebang 行

在 类 UNIX 系统中,shebang 行用来指定脚本的解释器路径,通常出现在第一行,格式如下

#! interpreter_path

shebang 行中开头 #! 字符的作用是告诉操作系统这不是一个普通二进制文件,而是需要通过解释器运行的东西

而这个解释器则通过 #! 字符后面来指定。例如 /bin/bash 表示使用 bash 解释器来执行该脚本文件

下面则是一些 Bash 脚本的 shebang 行,指定了不同的解释器

#! /usr/bin/perl
#! /usr/bin/awk
#! /usr/bin/python

那么这时候小伙伴们可能就会有疑问:我忘了加 shebang 行,脚本为什么还能执行?

如果一个脚本没有添加 shebang 行来指定解释器路径,则默认情况下系统会使用默认的 shell 来执行脚本,系统默认的 shell 可以通过下面的命令来查看

# 一般情况下默认的 shell 为bash
echo $SHELL

现在我们知道了 shebang 行的作用,那么我们现在来编写一个脚本并修改 shebang 行试试

test.sh 内容如下:

#!/bin/bash
echo Hello

先给 test.sh 脚本添加一下执行权限

chmod +x test.sh

接下来我们用几种方式来执行这个脚本



可以看到脚本都成功执行了

下面我们来改一下 shebang 行,将其改成其他命令

#!/usr/bin/ls -l
echo Hello

然后我们分别用几种方式来执行这个脚本



上面脚本执行的结果是不是看的一脸懵逼,说实话我一开始看到的时候也是很懵

我们先来看下这四种脚本执行方式的区别

  • bash tesh.sh

这种方式执行脚本的原理是将 test.sh 作为参数传给 bash 解释器(命令)来执行,而不是 test,sh 自己来执行

这种方式执行脚本不需要给脚本文件添加执行权限、不需要写 shebang 行指定解释器路径,因为脚本是作为参数被传给 bash 来执行

  • sh test.sh

这种执行脚本的方式跟上面的方式原理一样,都是将脚本作为参数传进去,只不过是这个方式用的是 sh 解释器(命令),而不是 bash

  • /root/test.sh

这种是通过绝对路径去执行脚本,通过绝对路径来执行脚本就需要脚本拥有执行权限

当使用绝对路径来执行脚本时,操作系统需要知道该脚本文件所使用的解释器类型,这就需要依靠脚本文件中的 shebang 行

实际上你用绝对路径执行脚本的时候,如果里面定义了 shebang 行(例如 #! /bin/bash

那么实际上跟下面的命令是一样的

/bin/bash /root/test.sh

在执行脚本的时候,操作系统会读取脚本的 shebang 行

如果你的 shebang 行是其他 Linux 命令而不是解释器,那么就会导致操作系统将你的 shebang 行当作命令,而你的脚本则是命令的参数

就好比上面的例子,我将 shebang 行改成了 #! /usr/bin/ls -l ,当我执行脚本的时候其实就是下面这样的

/usr/bin/ls -l /root/test.sh

这样会导致脚本无法执行

  • ./test.sh

这种是通过相对路径去执行脚本,跟上面用绝对路径执行脚本方式是一样的,只不过区别是一个是相对路径一个是绝对路径

总结:

  • shebang 行通常出现在 UNIX 系统的脚本当中,用来指定脚本的解释器路径,出现在第一行,以 #! 开头
  • 如果脚本里面没有定义 shebang 行,系统会去找默认的解释器,默认解释器用 echo $SHELL 查看
  • 用 bash 或者 sh 命令执行脚本的时候,其实是把脚本作为参数传给 bash 或 sh 命令了,这时候脚本可以不添加执行权限、可以不需要 shebang 行
  • 如果用绝对路径或者相对路径的方式来执行脚本,需要脚本拥有执行权限,如果 shebang 行定义的不是解释器而是其他命令,就会导致脚本无法执行

附上参考链接:Shebang Shenanigans :: Linus Karlsson

关于 Bash 脚本中 Shebang 的趣事的更多相关文章

  1. grep 查找bash脚本中的注释代码

    出于安全性的考虑,不建议在bash脚本中注释掉不使用的代码.也就是说如果某段代码不使用了,那么应该删除掉,而不是简单地注释掉.假如你突然意识到这一点,而以前并没有遵从这个原则,现在需要找出脚本中的注释 ...

  2. 如何在Bash脚本中引入alias

    更多精彩内容,请关注微信公众号:后端技术小屋 alias的使用 在日常开发中,为了提高运维效率,我们会用alias(命令别名)来定义命令的简称.比如在~/.bash_profile中添加: alias ...

  3. bash 脚本中分号的作用

    在Linux bash shell中,语句中的分号一般用作代码块标识 1.单行语句一般要用到分号来区分代码块.比如: weblogic@pmtest:/$if [ "$PS1" ] ...

  4. Bash脚本中的操作符

    一.文件測试操作符 假设以下的条件成立将会返回真. -e 文件存在 -a 文件存在 这个选项的效果与-e同样. 可是它已经被"弃用"了, 而且不鼓舞使用. -f 表示这个文件是一个 ...

  5. Bash 脚本中的 set -euxo pipefail

    有些开发人员会用Bash来实现很复杂的功能,就像使用别的高级语言一样.他可能觉得自己很牛逼但其他人早就想锤爆他了,Bash的可读性和可维护性远远低于任何高级语言.更要命的是,Bash并没有方便的调试工 ...

  6. 详解在bash脚本中如何获取自身路径

    DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 这是stac ...

  7. bash脚本中的普通数组和关联数组

    1. 普通数组 bash支持一维数组(不支持多维数组),并且没有限定数组的大小.类似与C语言,数组元素的下标由0开始编号.获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0. ...

  8. linux 环境下bash脚本中找不到命令

    mr.sh: line 1: HADOOP_CMD: command not found mr.sh: line 4: INPUT_FILE_PATH: command not found mr.sh ...

  9. bash脚本中使用选项 getopts

    原文链接 : http://note.youdao.com/noteshare?id=0cf08484c7308c763726e63e9a638ff5&sub=EF6A110E2F3345E6 ...

  10. Linux下shell脚本中信号捕获和函数练习脚本之ping一个网段

    该脚本主要的目的是练习在Linux bash脚本中捕获信号,顺便练习一下函数的使用,还有就是终止一个正在运行的程序后,该程序打开的文件的后续处理问题等等!脚本功能:  ping一个网段内的IP,检测哪 ...

随机推荐

  1. python求列表中某个值第一次出现的位置

    x=[2,1,1] print(x.index(1)) 结果为1

  2. rules验证数值大于0

    [['mobile'],'number'],[['mobile'],'compare','compareValue' =>0,'operator' => '>']compare对比, ...

  3. Apache Ranger系列七:Hive 和 Spark 执行过程中的文件路径配置

    背景:在使用Ranger鉴权的过程中,要求必须开启impersonation功能(即执行用户与提交用户保持一致,而不是统一代理的hive/spark).但是在执行的过程中,会需要在hdfs存储临时的文 ...

  4. 关于Windows10纯净启动的相关修改流程

    关于纯净启动的相关流程 自动登录 打开命令提示符运行control userpasswords2后回车 在弹出的用户账户窗口中,取消勾选"要使用本计算机,用户必须输入用户名和密码" ...

  5. linux查看已知进程PID所在的目录

    pwdx 命令 pwdx PID [was@CMTRMWAS1 ~]$ pwdx 31996 31996: /was/AppServer/profiles/AppSrv03

  6. [rk3568][buildroot] 移除RK3568 iodomain check

    1. 问题背景 RK3568 基线代码默认会起一个服务监控RK3568 iodomain,该服务间隔性输出log信息: 由于该功能非必要,故选择移除该部分逻辑 2.解决方案 查看源码编译脚本,如下图所 ...

  7. Spring源码构建踩坑记录

    1:Kotlin: warnings found and -Werror specified Kotlin将程序中的警告变更为错误导致的问题,只需要改变一下级别即可,注意看是那个模块的 解决方式:fi ...

  8. C/C++编译构建相关问题

    名词辨析 GNU GNU's Not Unix!的递归缩写 一个自由的操作系统,起源于GNU计划,希望发展出一套完整的开放源代码操作系统来取代Unix 基本组成包括: GNU编译器套装(GCC) GN ...

  9. Linux耳机音响独立输出

    记得之前在用Ubuntu系统的时候,耳机和音响(线缆输出和模拟耳机输出)只能单独插一个,如果两个设备同时插入主机,将会导致只能耳机输出,即使选择后置音响(线缆输出)也不会有声音.在Windows下,即 ...

  10. java多线程基础小白指南--关键字识别(start,run,sleep,wait,join,yield)

    在学习java多线程基础上,会遇到几个关键字,理解并识别它们是掌握多线程的必备知识,下面,我将通过源码或者程序演示给出我对这几个关键字的理解,如果有不同意见,欢迎在评论区或者发私信与我探讨. 一.st ...