初识 #!
我们经常在一些脚本的第一行看到#!
开头的一段注释,例如在shell
脚本中:
|
|
在python
脚本中:
|
|
在我们熟知的几种脚本语言中,#
一般被用作单行注释
。但在类Unix
环境下,第一行的#!
还有另外一层意义:它告诉操作系统(程序加载器
,即 program loader
),在运行脚本时,使用哪一个解析指令(interpreter directive)
来处理脚本。这一行特殊注释,称为shebang
,也叫做sh-bang
、sha-bang
、hashbang
、pound-bang
、hash-bang
。
在上面的示例中,shebang
指明分别使用/usr/bin/bash
和/usr/bin/python
来分别运行shell
和python
脚本,最终打印hello world!
。
shebang
定义
shebang
的格式:
|
|
其中:
shebang
必须出现在脚本第一行,且顶格。interpreter
是一个可执行程序
,并用绝对路径
或者基于当前工作目录的相对路径
写明。这里可执行程序
的定义在不同操作系统上定义不同。在Linux
中,可执行程序
是指具有可执行权限的、可以直接运行的程序,可以是可执行二进制程序,也可以是脚本。在Solaris-
和Darwin-
的衍生操作系统中(比如MacOS
),可执行程序
是指可执行的二进制程序,而不能是脚本。#!
与interpreter
之间可以有空格,但通常不使用空格。- 可以传递多个参数。
调用示例
在/tmp/
目录下新建shebang
目录,目录结构:
|
|
myscript_a
:
|
|
myscript_b
:
|
|
在myscript_a
使用bash
作为解析指令
,输出第一个参数,并且显示对应文件内容。
在myscript_b
使用myscript_a
作为解析指令
,最终会当作文本显示全部内容。
先添加脚本的可执行权限,然后执行:
[leo@leo-m shebang]$ chmod +x myscript_*
[leo@leo-m shebang]$ ./myscript_b
./myscript_b
#!/tmp/shebang/myscript_a
echo hello world
我们可以看到,脚本的运行效果如同脚本的直接调用:
[leo@leo-m shebang]$ ./myscript_a ./myscript_b
./myscript_b
#!/tmp/shebang/myscript_a
echo hello world
使用env的shebang
使用env的目的
env
作为一个命令,经常被用来列举当前用户的所有环境变量。而我们也常在shebang
中使用它。
拿python
脚本举例,这种写法也经常出现:
|
|
虽然最终都是使用python
来解析脚本,那么它跟#!/usr/bin/python
有何区别呢?
其实,使用env
的方式,只是比直接指定路径的方式,多了一些灵活性。env
会在环境变量PATH
中查找python
所在路径,最终使用找到的第一个python
来解析脚本。我们可以使用echo $PATH
在终端查看自己的PATH
目录。
使用env
的方式,最大的优势
就是实现不同环境上的兼容性。因为在不同的系统中,python
等可执行程序可能存在的目录不一样。举个例子,python
可能放在/usr/bin
下,或者/opt/python
、$HOME/python
等目录(当然这些目录需要添加到PATH
环境变量中,env
才能找到),如果直接指定指定/usr/bin/python
导致找不到python
,最终无法正常执行。
使用env
也有一个小风险,就是恶意人士可能在PATH
目录下放置一个同名的假程序,脚本执行时就会运行这个恶意程序。当然这个操作需要一定的权限(比如root
、或者其它具有sudo
等授权),当他都拥有了这种权限之后,可能也不屑于做这样的事了。
env 的shebang定义
|
|
我们看个容易出错误
的地方,用perl
作例子,文件名hello.pl
:
|
|
脚本只是输出hello
,但尝试运行时出错:
[leo@leo-m shebang]$ chmod +x hello.pl
[leo@leo-m shebang]$ ./hello.pl
/usr/bin/env: “perl -T -w”: 没有那个文件或目录
/usr/bin/env: 使用 -[v]S 以在 shebang 行中传递选项
错误信息中可以看出,env
的把perl -T -w
整个一串当成程序名,肯定找不到了。
那么使用env
如何传参数呢?那就是使用-S
选项,看hello_u.pl
:
|
|
脚本需要环境变量USER
(单纯想展示一下使用env
写法还可以临时设置环境变量的优势功能),我们通过env
的参数指定为neochin
。-S
是split
分割的意思,就是指明后面的字符串要拆开来解析。运行效果:
[leo@leo-m shebang]$ chmod +x hello_u.pl
[leo@leo-m shebang]$ ./hello_u.pl
hello neochin
灵活的注释
在日常开发过程中,并非所有的注释都是只是给程序员看的。
比如在python2
时代,我们通常使用单独一行注释# -*- coding: utf-8 -*-
,指定python
脚本的默认编码为utf-8
。
[leo@leo-m tmp]$ cat p.py
print("中文")
[leo@leo-m tmp]$ python2 p.py
File "p.py", line 1
SyntaxError: Non-ASCII character '\xe4' in file p.py on line 1,
but no encoding declared;
see http://python.org/dev/peps/pep-0263/ for details
[leo@leo-m tmp]$
[leo@leo-m tmp]$
[leo@leo-m tmp]$ cat p1.py
# -*- coding: utf-8 -*-
print("中文")
[leo@leo-m tmp]$ python2 p1.py
中文
又比如在团队协作时,通常需要输出
API文档
。为了减少单独编写及维护成本,我门通常使用第三方文档工具swagger
,doxygen
等,通过扫描代码、注释来完成文档的自动化生成。
同时,注释还很好玩。用一个源码文件,支持不同语言运行,请看Polyglot。起飞吧,少年,秀儿就是你!
参考资料
打不开链接的,请科学上网。