关于解释器
脚本脚本第一行一般会写解释器路径,常见的:
1
2
3
#!/bin/bash
#!/usr/bin/bash
#!/usr/bin/env bash
这样算是比较规范的写法。如果使用脚本时,脚本文件名是作为参数跟在解释器程序后面的,则写不写是不影响的。如:
1
2
/usr/bin/bash mytest.sh # sh后缀仅用于帮助用户区分文件类型,可以不写,一般会使用sh后缀表示shell脚本
/usr/bin/python mytest.py # python 脚本一般使用py后缀
以上,使用指定的解释器解释运行后面的”文本文件“时,第一行可以不写解释器路径,因为”文本文件“就是由指定的解释器运行的。 当把”文本文件“作为可执行程序运行时,第一行应当写明解释器路径。如:
1
2
3
chmod a+x ./mytest.sh ./mytest.py
./mytest.sh
./mytest.py
以上,即作为可执行文件直接运行。第一行一般以#!
开头,跟一个对应的解释器路径,用于解释运行该文件。
在linux系统中,如果运行该可执行文件,linux内核代码首先会根据可执行文件开头的几个字节来判断可执行文件的类型。如ELF可执行文件 开头几个字节就是固定的magic number .ELF
,java语言的class文件开头也是有固定的magic number cafe
。文件的后缀仅帮助 用户方便区分文件类型,真正的起类型区分作用的是可执行文件开头的magic num,一般不超过4个字节。脚本文件作为可执行文件运行时, 也是同理,而脚本文件的magic num则是 #!
。
linux内核发现#!
后,将其作为脚本文件运行,后序调用不同的接口来实现“执行”该文件。体现在用户层面就是规定: #!
后面写一个 解释器路径,内核会加载对应的解释器,用解释器来加载运行脚本文件。 所有的脚本可执行文件都是同理的,如 sh,bash,zsh,fish,csh,python,python3,ruby,perl,awk
等等。原理相同。
解释器指定方式
脚本文件指定解释器一般有两种方式。以bash
为例。
精确指定
1
2
#!/bin/bash
#!/usr/bin/bash
这种最常见,可以精确指定对应的解释器程序路径,并且可以带命令行参数。仅有一个主要问题,不同发行版,这个解释器放的路径可能不一样, 如果出现没有放在对应路径时,需要手动稍微调转。因此,还有另一种方式
env查找
1
2
#!/usr/bin/env bash
#!/usr/bin/env python
这种写法,通过env
在该用户$PATH环境变量
中来查找对应名称的解释器,并用来加载运行脚本。不支持解释器带命令行参数。这种方式,主要在不同发行版中兼容性较好。(只要能能PATH环境变量中能找到这个解释器即可)。主要问题:无法确定到底是用哪个解释器在运行,尤其是在PATH环境变量中有多个同名的解释器时,这样就有一些不确定隐患。另外,由于需要env查找,如果需要频繁运行该脚本,这种方式效率不如直接指定的方式。
个人小结
- 如果不考虑兼容性,还是直接指定,主流的发行版一般都支持
/bin/bash
或/usr/bin/bash
,精确高效明了。 - 如果考虑兼容性更重要,对性能要求不高,可以使用 env 方式查找指定。