初识 #!
我们经常在一些脚本的第一行看到#!开头的一段注释,例如在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。起飞吧,少年,秀儿就是你!
参考资料
打不开链接的,请科学上网。