shell
参考书籍:Linux程序设计中文第4版–第2章
编译型与解释型语言
C/C++语言是编译型语言。
即完成的代码是不可以直接执行的,需要编译器进行编译连接生成相应的二进制指令,二进制指令可以直接在计算机上运行。效率很高
java语言是编译型和解释型语言。
java代码会编译成.class文件,.class文件编译好之后就可以一次编译到处运行。因为java语言会在不同平台的计算机上安装一个java虚拟机,java虚拟机不是跨平台的,不同平台需要安装不同系统的虚拟机。但是编译生成的.class文件是可以跨平台的,.class文件可以通过java虚拟机屏蔽不同系统底层的差异。因此.class文件是通过java虚拟机解释执行的
脚本文件:一般以.sh结尾
脚本文件是一个文本文件,不能在计算机上执行,因此就需要一个解释器,边解释边执行
shell是什么
shell编程
- #!指定解释器
也可以不写,直接使用系统默认的解释器
单独#表示屏蔽或注释
python 脚本编程
python3不兼容python2
虚拟机安装python2: sudo apt install python2
使用脚本编程的原因
脚本程序虽然不能直接在计算机上运行,效率底下。但是完成同样功能,使用脚本程序速度快(不是运行速度快,而是开发的速度快)。
脚本程序为什么快?
因为shell脚本压根就没有干事情,他是通过调用命令完成的,而命令是提前写好的二进制程序。所以脚本程序就像搭积木一样,把不同的命令组合在一块,满足某个条件就执行,该循环就循环…从而可以很快速的达到目的,完成某个功能
示例:
场景:一个文件中存放有浮点数,现需要将浮点数的整数部分提取出来存放到另外一个文件中
使用shell编程仅需要一行代码,但是使用c语言却很繁琐
脚本编程–变量
在C或者C++语言中定义变量必须指定类型,类型决定了开辟多大的内存空间。但是脚本程序定义变量和编译型语言完全不同
本地变量:用户自己定义的变量
脚本程序中变量不谈类型,定义变量只需要变量名和变量的值
命令:echo==print 都是打印的命令,只不过echo比print出现早
- 原样打印字符串:echo str
- 打印变量值 : echo $str :意思是取str变量的值
- 双引号–>意思是弱引用,并不能影响到对变量的取值,只是标识双引号内的数据是一个整体
- 单引号–>意思是强引用,可以将单引号内的内容原样输出,单引号内的变量已经失去了取值的能力,已经变成了像C语言字符串常量
- 定义变量时等号两边不能有空格
变量获取值
方式一:用户定义时直接赋值
方式二:变量给变量赋值或者一个命令执行的结果给一个变量赋值
方式三:从键盘获取值
环境变量:
父进程定义好的变量,子进程继承过来的变量
简单来讲,自己没有定义该变量,但是可以使用该变量
$PATH:默认可执行文件存放的地点
$PS1:一级提示符
$0:当前shell脚本的名字
$#:传递给脚本的参数个数
$$:解释脚本程序的解释器进程的id
参数变量
脚本程序如何拿到参数
$1,$2,$3…$9 :脚本程序的参数
$* :传递给脚本程序的所有参数
获取传递给脚本的参数
脚本编程–条件
text 或者 [ 命令:测试后面的条件是否满足
字符串比较
- 字符串是否相等
- 字符串是否为空
算术比较
算术比较必须是一个纯数字,不能掺杂字母
文件条件测试
脚本程序中如何执行命令
脚本文件中可以输入命令,运行脚本程序可以执行相应命令
将命令执行的结果赋值给变量
方式一:$()
方式二:使用反引号将命令引入
对变量值进行自加
方式一:let命令
方式二:expr
脚本编程–循环
for语句:对有限的内容进行操作
变量在values中取值,值有多少,意味着变量可以取多少次值,也就意味着循环多少次。循环体在do和done之间
while循环
1.死循环
条件为真的情况:
2.退出循环
until循环
一直做,直到事情成功为止
脚本编程–case语句
脚本编程–函数
函数需要声明,所以函数需要写在脚本的最开始
脚本函数不用写返回值,不用写参数列表(当然脚本函数是可以传参的);因此就不存在返回值类型和参数类型。最终解释器会按照合适的方式对字符串进行相应解释。
函数如何传参
$1,$2…$9
如果写在函数之外代表是传递给脚本程序的参数
如果写在函数内部代表是传递给函数的参数
如何拿到函数返回值
情境1:没有return语句,需要返回值
情境2:有return语句
函数内部定义变量的特点
脚本程序无论在哪里定义变量,无论是函数内部,函数外,都是在解释器里面定义的变量,只要在解释器中定义,解释器对于变量的引用都是一样的,无论在解释器任何位置都是可以引用变量的值。如果在其他地方定义了同名变量,那么解释器也只是认为修改了该变量的值,而不是重新定义变量。只有等到解释器进程结束,终止,解释器里面定义的变量就没有了。
local:仅本作用域可见
如果在函数内部定义变量前面加上local,那么该变量就只能在函数体可见,出函数就没有了,就从解释器中移除了
unset:移除变量
该方法在脚本调用脚本时很常见。因为以点的方式调用脚本就意味着在当前解释器中执行调用脚本,如果被调用脚本中有同名变量就很容易把变量值修改,因此用完后不用就移除可以避免很多不必要的麻烦
脚本编程–脚本调用脚本
只需要在脚本中将想要调用的脚本的 路径+名称 给出了就可以实现脚本调用脚本
当在一个脚本中给出另一个脚本的路径+名称时,就会重新启动一个解释器来解释执行想要调用的脚本
如何让一个脚本中的变量在另一个脚本中可以使用
方法一:将变量做成环境变量(最安全)
- export
环境变量是可以被子进程继承的。在当前执行a脚本程序的解释器中重新启动一个解释器执行b脚本。那么执行b脚本的解释器就是执行a脚本解释器的子进程。
方法二:将变量当成参数传递给被调用脚本
方法三:以点 命令执行调用脚本
以点 命令执行调用脚本:
意味着想要将b脚本放到当前解释器中执行。及就是将b脚本的命令复制粘贴到当前位置,然后在当前解释器解释执行
等价于:
等价于:
脚本编程–C程序中调用脚本
使用C程序调用脚本使得程序的灵活性提高,即使C程序已经编译链接变成了二进制可执行文件,此时依然可以改变脚本程序。因为脚本程序是后期调用的,并不参与编译
直接执行脚本程序
C程序调用脚本程序
脚本程序调用C程序
脚本中调用的所有命令本质都是可执行程序
脚本编程–命令
awk:文本过滤工具
操作:对文件中的内容进行过滤或者提取或者生成一个报文,让用户可以去看。即读取源文件,把用户想要的信息提取出来,不需要的就不呈现
示例1:打印单个域的值
示例2:打印2个域的值
示例3:加判断语句,打印一整行
示例4:提取命令结果中的某一个域
示例5:
使用要求
操作的文件必须要有明确的行和列
操作过程
awk 过滤后呈现的是某一个域的值,操作过程并不是直接可以得到一个域的数据;而是一行一行的进行读取,遇到用户想呈现的数据就打印,否则丢弃。操作过程并不改变源文件
sed:非交互性流式文本编辑器
一个流式的文本编辑器
可以对一个文件进行修改,对文件内容进行简单的编辑,但是不改变源文件
示例1:向指定文件中指定行插入内容
示例2:向指定文件中指定行附加内容
附加内容无法插入到第一行