关于shell你可能忽略的一些冷知识

250 阅读7分钟

引子

你听过”shebang“这个词吗?它其实就是你在shell文件头部写的那个#!,如果你理解它的含义和作用,就不会在拼写的时候手忙脚乱了。

shebang

shebang,也称hashbang,它表示”#!“这一对字符。

因为计算机中某些场景也使用井号#表示哈希(hash)

含义

它的含义正如这个单词的组成,就是sharp + bang结合在一起后的简写形式。其中的sharp源于乐谱中的升音符,也就是下图中的”井号“。而bang则表示感叹号。(!!!bang bang bang)

C#读作”C sharp“也是如此。

image.png

图片引用自zh.wikipedia.org/wiki/%E5%8D…

作用

当文本文件第一行前两个字符#!时,类Unix操作系统(见下图)的程序加载器会分析后面的内容,在#!后面可以有空白字符,再后面紧跟着的应是解释器的绝对路径

1280px-Unix_history-simple.svg.png

图片引用自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命令,在Python2PerlRuby中都有类似的语法,那么当你在文件中只写下一行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可以看到都有哪些全局可执行文件,其中不乏一些我们常用的命令,比如pwdlsrmcatmkdirmv等等,还有我们刚刚用于修改文件权限的chmod命令。

用户可执行文件

/usr/bin则表示当前用户有哪些可执行文件,那么/usr/bin下都有哪些当前用户的可执行命令呢,那就多了。

而且随着你在本机安装各种程序,一些非系统自带的程序也可能向该目录新增一些可执行文件。其中有些可执行文件可能是指向(链接)另一处目录的某个文件,我们可以通过type命令查看其真实所在的位置。

思考

那么讲了这么多#!是什么以及怎么用,我们可能还是不能直观感受到它的存在价值。关于其核心用途,维基百科上有一个官方的解释。

解释器指令允许脚本和数据文件充当系统命令,无需在调用时由用户指定解释器,从而对用户和其它程序隐藏其实现细节。

怎么理解这个解释呢,其实我们上述所做的实验就已经验证了这一结论。

当我们在某个文本文件第一行使用了#!并在其后声明了有效的解释器绝对路径,该文件就变成了可执行文件,也就是上述解释中所说的”充当系统命令“。

当你在控制台输入一串字符,计算机会分别去/bin/usr/bin下寻找有没有同名的可执行文件,也就是系统/用户命令。如果没找到就会接着解析该文件是否有在第一行通过#!进行解释器声明,如果也没有自然会执行失败。

而上面所说的”无需在调用时由用户指定解释器“,指的就是我们对于一个文件无需使用sh testpython testruby testperl test这种方式去指定解释器。它的价值也写的很清楚,就是”对用户和其他程序隐藏其实现细节“,也就是你不用关心这个文件的具体实现,只需直接执行即可。

一般这种文件会通过文件名结合帮助手册来指导使用者它可以完成的任务。

常用工具总结

这里再补充一些控制台可用但不常用的命令(类unix系统)

命令含义作用
calcalendar输出日历
datedate输出当前日期
bcbasic calculator简易计算器
pwdprint working directory输出当前路径
typetype输出后续紧跟命令的类型
filefile输出后续紧跟文件的类型
timetime计算后续紧跟命令的执行时间
psprocess status显示当前运行的进程
killkill结合ps使用终止指定进程
clearclear清除屏幕
echoecho输出命令参数到标准输出
grepglobally search a regular expression and print以正则表达式进行全局查找并打印

还有一些大家熟知并常用的命令

命令含义作用
lslist列出文件
cdchange directory切换目录
mkdirmake directory创建目录
cpcopy拷贝文件
mvmove移动文件(也可用于修改文件名称)
rmremove删除文件或目录
chmodchange mode修改文件权限

小结

本篇是我围绕shebang含义展开学习并总结的一系列shell知识,借此系统地梳理了类unix系统下的一些常用命令,如有错误或不准确的地方欢迎指正。

linux环境是很多程序员在职业生涯大多无法绕开的经典领域,这里面既有伟大的开源思想,也保留着计算机最原始的交互方式——命令行,更多的是其为程序员与计算机打交道时提供了众多强有力的高效工具,掌握好这些知识势必会让我们对于计算机的控制达到事倍功半的效果。