关于 Bash 脚本中 Shebang 的趣事
哈喽大家好,我是咸鱼
不知道小伙伴们在写 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 的趣事的更多相关文章
- grep 查找bash脚本中的注释代码
出于安全性的考虑,不建议在bash脚本中注释掉不使用的代码.也就是说如果某段代码不使用了,那么应该删除掉,而不是简单地注释掉.假如你突然意识到这一点,而以前并没有遵从这个原则,现在需要找出脚本中的注释 ...
- 如何在Bash脚本中引入alias
更多精彩内容,请关注微信公众号:后端技术小屋 alias的使用 在日常开发中,为了提高运维效率,我们会用alias(命令别名)来定义命令的简称.比如在~/.bash_profile中添加: alias ...
- bash 脚本中分号的作用
在Linux bash shell中,语句中的分号一般用作代码块标识 1.单行语句一般要用到分号来区分代码块.比如: weblogic@pmtest:/$if [ "$PS1" ] ...
- Bash脚本中的操作符
一.文件測试操作符 假设以下的条件成立将会返回真. -e 文件存在 -a 文件存在 这个选项的效果与-e同样. 可是它已经被"弃用"了, 而且不鼓舞使用. -f 表示这个文件是一个 ...
- Bash 脚本中的 set -euxo pipefail
有些开发人员会用Bash来实现很复杂的功能,就像使用别的高级语言一样.他可能觉得自己很牛逼但其他人早就想锤爆他了,Bash的可读性和可维护性远远低于任何高级语言.更要命的是,Bash并没有方便的调试工 ...
- 详解在bash脚本中如何获取自身路径
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 这是stac ...
- bash脚本中的普通数组和关联数组
1. 普通数组 bash支持一维数组(不支持多维数组),并且没有限定数组的大小.类似与C语言,数组元素的下标由0开始编号.获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0. ...
- linux 环境下bash脚本中找不到命令
mr.sh: line 1: HADOOP_CMD: command not found mr.sh: line 4: INPUT_FILE_PATH: command not found mr.sh ...
- bash脚本中使用选项 getopts
原文链接 : http://note.youdao.com/noteshare?id=0cf08484c7308c763726e63e9a638ff5&sub=EF6A110E2F3345E6 ...
- Linux下shell脚本中信号捕获和函数练习脚本之ping一个网段
该脚本主要的目的是练习在Linux bash脚本中捕获信号,顺便练习一下函数的使用,还有就是终止一个正在运行的程序后,该程序打开的文件的后续处理问题等等!脚本功能: ping一个网段内的IP,检测哪 ...
随机推荐
- 使用npm包API Promise化
- ORACLE数据库通过DBLINK连接另一个数据库
ORACLE数据库通过DBLINK连接另一个数据库 亲测有效:create database link XXX --dblink名connect to 远程数据库用户名 identified by & ...
- MQ(部署模式)
MQ部署模式 1.master-slave部署模式 1)shared filesystem Master-Slave部署方式 主要是通过共享存储目录来实现master和slave的热备,所有的Acti ...
- 自定义DOM事件函数封装
非原生DOM触发,个性化定制的自定义事件. currentTarget(DOM对象):要触发事件的元素节点. type(字符串):触发的事件类型,例如"keydown". bubb ...
- Tcp网络模型
要摸清网络,那么第一步肯定是要清楚网络协议的分层结构,用上帝视角来看网络. 对于同一台设备上的进程间通信,有很多种方式,比如有管道.消息队列.共享内存.信号等方式,而对于不同设备上的进程间通信,就需要 ...
- AttributeError: module 'torch._six' has no attribute 'PY3'
修改:进到torch._six源码,看看里面是PY的哪个对象,修改成这对象名试试 _six.py 即将PY3修改为PY37
- SHELL-反弹shell
什么是shell? 在我们深入了解发送和接收 shell 的复杂性之前,了解 shell 实际上是什么很重要.用最简单的术语来说,shell 就是我们在与命令行环境 (CLI) 交互时使用的工具.换句 ...
- 快速部署LAMP黄金架构,搭建disuz论坛
快速部署LAMP架构 [root@zhanghuan ~]# iptables -F[root@zhanghuan ~]# systemctl stop firewalld[root@zhanghua ...
- Linux值得收藏的40个命令总结,常用的正则表达式
1 删除0字节文件 find -type f -size 0 -exec rm -rf {} \; 2 查看进程 按内存从大到小排列 PS -e -o "%C : %p : %z : %a& ...
- 一文读懂字符编码ASCII、Unicode与UTF-8
先说一下,为什么写这篇文章? 最近在写一个Http协议栈当涉及CRLF控制字符写入时,发现自己对CRLF与\r\n的关系不太了解,因此决定详细学习一下:查阅资料的同时,又遇到UTF-8与ASCII编码 ...