引子
你听过”shebang“这个词吗?它其实就是你在shell文件头部写的那个#!
,如果你理解它的含义和作用,就不会在拼写的时候手忙脚乱了。
shebang
shebang,也称hashbang,它表示”#!“这一对字符。
因为计算机中某些场景也使用井号#表示哈希(hash)
含义
它的含义正如这个单词的组成,就是sharp + bang
结合在一起后的简写形式。其中的sharp
源于乐谱中的升音符
,也就是下图中的”井号“。而bang
则表示感叹号。(!!!bang bang bang)
C#
读作”C sharp“也是如此。
图片引用自zh.wikipedia.org/wiki/%E5%8D…
作用
当文本文件第一行
的前两个字符
是#!
时,类Unix操作系统(见下图)的程序加载器会分析后面的内容,在#!
后面可以有空白字符,再后面紧跟着的应是解释器的绝对路径
。
图片引用自zh.wikipedia.org/wiki/%E7%B1…
也就是当一个文本文件的第一行含有#!
这个符号后,该文件就变成了可执行文件,而执行该文件的解释器将会由#!
后面所声明的内容指定。
实例演示
比如我们创建一个test.sh文件如下
#!/bin/sh
echo "hello from shell"
然后在控制台直接输入该文件名./test.sh
就可以执行文件内的内容,因为该文件由于第一行的内容而变成了可执行文件
。
执行文件的前提是你拥有该文件的执行权限,如果没有可通过 chmod a+x 文件名 来为该文件增加所有角色的执行权限
反之,如果没有第一行,你直接执行这个文件可不可行呢?
echo "hello"
好像也可以,这是因为shell环境下默认会将可执行文件以shell解释器进行解释执行。
但如果你在文件中写的是非shell可执行的命令呢,比如下面这样
print "hello"
执行该文件会报出line 1: print: command not found
这样的错误提示,这是因为你直接执行一个文本文件,它会默认使用全局的shell解释器去执行这个文件,作用相当于sh test.sh
,但由于文件中写的不是shell
可识别的命令,因此会执行失败。
对于这类情况,我们就需要通过#!
进行解释器的声明。比如对于print
命令,在Python2
、Perl
和Ruby
中都有类似的语法,那么当你在文件中只写下一行print "hello"
的时候,程序执行器是不知道应该如何解释该文件的,这也就是#!
的关键作用了。
我们可以通过#!
进行解释器的声明如下
使用python解释器
#!/usr/bin/python2
print "hello from python2"
使用perl解释器
#!/usr/bin/perl
print "hello from perl\n"
使用ruby解释器
#!/usr/bin/ruby
print "hell from ruby\n"
这三种情况,通过直接输入文件名./test
都能执行成功,这是因为文件中声明了解释该文件的对应解释器。
可执行文件
那么如何知道我们的系统中都有哪些可用的解释器呢,其实只需要在/bin
和/usr/bin
下寻找即可。我们都知道binary既是二进制的意思,在计算机中也表示可执行文件,其一般简写为bin
。
系统可执行文件
/bin
表示系统全局有哪些可执行文件,我们使用cd /bin
进行到系统根目录下的可执行文件目录,然后通过ls
可以看到都有哪些全局可执行文件,其中不乏一些我们常用的命令,比如pwd
、ls
、rm
、cat
、mkdir
和mv
等等,还有我们刚刚用于修改文件权限的chmod
命令。
用户可执行文件
/usr/bin
则表示当前用户有哪些可执行文件,那么/usr/bin
下都有哪些当前用户的可执行命令呢,那就多了。
而且随着你在本机安装各种程序,一些非系统自带的程序也可能向该目录新增一些可执行文件。其中有些可执行文件可能是指向(链接)另一处目录的某个文件,我们可以通过type
命令查看其真实所在的位置。
思考
那么讲了这么多#!
是什么以及怎么用,我们可能还是不能直观感受到它的存在价值。关于其核心用途,维基百科上有一个官方的解释。
解释器指令允许脚本和数据文件充当系统命令,无需在调用时由用户指定解释器,从而对用户和其它程序隐藏其实现细节。
怎么理解这个解释呢,其实我们上述所做的实验就已经验证了这一结论。
当我们在某个文本文件第一行使用了#!
并在其后声明了有效的解释器绝对路径,该文件就变成了可执行文件,也就是上述解释中所说的”充当系统命令“。
当你在控制台输入一串字符,计算机会分别去/bin
和/usr/bin
下寻找有没有同名的可执行文件,也就是系统/用户命令。如果没找到就会接着解析该文件是否有在第一行通过#!
进行解释器声明,如果也没有自然会执行失败。
而上面所说的”无需在调用时由用户指定解释器“,指的就是我们对于一个文件无需使用sh test
、python test
、ruby test
或perl test
这种方式去指定解释器。它的价值也写的很清楚,就是”对用户和其他程序隐藏其实现细节“,也就是你不用关心这个文件的具体实现,只需直接执行即可。
一般这种文件会通过文件名结合帮助手册来指导使用者它可以完成的任务。
常用工具总结
这里再补充一些控制台可用但不常用的命令(类unix系统)
命令 | 含义 | 作用 |
---|---|---|
cal | cal endar | 输出日历 |
date | date | 输出当前日期 |
bc | b asic c alculator | 简易计算器 |
pwd | p rint w orking d irectory | 输出当前路径 |
type | type | 输出后续紧跟命令 的类型 |
file | file | 输出后续紧跟文件 的类型 |
time | time | 计算后续紧跟命令的执行时间 |
ps | p rocess s tatus | 显示当前运行的进程 |
kill | kill | 结合ps使用终止指定进程 |
clear | clear | 清除屏幕 |
echo | echo | 输出命令参数到标准输出 |
grep | g lobally search a re gular expression and p rint | 以正则表达式进行全局查找并打印 |
还有一些大家熟知并常用的命令
命令 | 含义 | 作用 |
---|---|---|
ls | l is t | 列出 文件 |
cd | c hange d irectory | 切换 目录 |
mkdir | m ak e dir ectory | 创建 目录 |
cp | c op y | 拷贝 文件 |
mv | m ov e | 移动文件(也可用于修改文件名称) |
rm | r em ove | 删除文件或目录 |
chmod | ch ange mod e | 修改文件权限 |
小结
本篇是我围绕shebang
含义展开学习并总结的一系列shell
知识,借此系统地梳理了类unix
系统下的一些常用命令,如有错误或不准确的地方欢迎指正。
linux
环境是很多程序员在职业生涯大多无法绕开的经典领域,这里面既有伟大的开源思想,也保留着计算机最原始的交互方式——命令行,更多的是其为程序员与计算机打交道时提供了众多强有力的高效工具,掌握好这些知识势必会让我们对于计算机的控制达到事倍功半的效果。