shell就是用户与linux系统沟通的桥梁,我们想让Linux系统去做什么事情,就通过这个shell去执行对应的操作就行了。
shell编程其实就是把之前在shell中执行的单个命令按照一定的逻辑和规则,组装到一个文件中,后面执行的时候就可以直接执行这个文件了,这个文件我们称之为shell脚本。
The first shell
shell脚本的第一行内容是: #!/bin/bash
所有的编程语言学习的开始都是从打印hello world开始,那么我也用shell打印hello world
Shell 变量
掌握了shell脚本的基本格式以后,我们就需要学习一些开发脚本的细节内容了
shell中变量的命名要求:
只能使用数字、字母和下划线,且不能以数字开头
变量赋值是通过"="进行赋值,在变量、等号和值之间不能出现空格!
下面我们来创建一些变量,执行之后提示-bash: name: command not found的都表示是错误的,执行成功的话是没有任何输出的,没有反馈就是最好的结果
调用变量操作
变量分类
shell中的变量可以分为四种,
- 本地变量
- 环境变量
- 位置变量
- 特殊变量
这些变量都有什么区别呢?
本地变量
首先来看本地变量
本地变量的格式是VAR_NAME=VALUE,其实就是我们刚才在shell中那样直接定义的变量,这种变量一般用于在shell脚本中定义一些临时变量,只对当前shell进程有效,关闭shell进程之后就消失了,对当前shell进程的子进程和其它shell进程无效,
注意了,我们在这开启一个shell的命令行窗口其实就是开启了一个shell进程
克隆一个会话,
在这两个shell进程中执行echo $name 会发现在克隆的shell进程中获取不到name的值,表示本地变量对其它shell进程无效,
那这里面的对当前shell进程的子进程无效是怎么回事呢?
我们先执行pstree命令查看一下当前的进程树信息,但是会发现提示命名找不到
先安装 psmisc
执行pstree 系统变量如下
环境变量
接下来看一下shell中的环境变量,这里的环境变量类似于windows中的环境变量,例如在windows中设置JAVA_HOME环境变量
它的格式为:export VAR_NAME=VALUE
它的格式是在本地变量格式的基础上添加一个export参数
环境变量的这种格式主要用于设置临时环境变量,当你关闭当前shell进程之后环境变量就消失了,还有就是对子shell进程有效,对其它shell进程无效
注意了,在实际工作中我们设置环境变量一般都是需要让它永久生效,这种临时的并不适用,如何设置为永久的呢?
其实就是把这个临时的设置添加到指定配置文件中,以后每次开启shell进程的时候,都会去加载那个指定的配置文件中的命令,这样就可以实现永久生效了
在这里我们一般添加到/etc/profile文件中,这样可以保证对所有用户都生效
加入后 别忘了激活/etc/profile
位置变量
接下来看一下位置变量
在进行shell编程的时候,有时候我们想给shell脚本动态的传递一些参数,这个时候就需要用到位置变量,类似于$0 $1 $2这样的,$后面的数字理论上没有什么限制,
它的格式是:location.sh abc xyz
位置变量其实相当于java中main函数的args参数,可以在shell脚本中动态获取外部参数
这样就可以根据外部传的参数动态执行不同的业务逻辑了。
在后面的学习中大家会经常看到位置变量的使用形式
我们来演示一下
创建一个脚本文件,location.sh 在里面打印一下这些位置变量看看到底是什么内容
执行脚本sh location.sh abc xyz
结果发现
$0的值是这个脚本的名称
$1 是脚本后面的第一个参数
$2是脚本后面的第二个参数
$3为空,是因为脚本后面就只有两个参数
理论上来说,脚本后面有多少个参数,在脚本中就可以通过$和角标获取对应参数的值。
多个参数中间使用空格分隔。
特殊变量
$?
它表示是上一条命令的返回状态码,状态码在0~255之间
状态码 描述
0 命令成功结束
1 通用未知错误
2 误用Shell命令
126 命令不可执行
127 没找到命令
128 无效退出参数
128+x Linux信号x的严重错误
130 命令通过Ctrl+C控制码越界
255 退出码越界
变量和引号的特殊使用
首先是单引号,'':单引号不解析变量
然后再看一下双引号,"":双引号解析变量
反引号是执行并引用命令的执行结果,在这里反引号是获取到了name变量的值,然后去执行这个值,结果发现没有找到这个命令
如果我们把name的值改为pwd,来看一下效果,这样就会执行pwd,并且把pwd执行的结果打印出来。
有时候我们想在变量的值外面套一层引号,该怎么写呢?
shell中的循环和判断
for循环
首先来看for循环,for循环本身的意义我就不再赘述了,我们直接来看一下shell中for循环的格式特点
第一种格式:和java中的for循环格式有点类似,但是也不一样
第二种格式
while循环
while循环主要适用于循环次数未知,或不便于使用for直接生成较大列表时
下面来演示一下,创建 while1.sh,注意,这里面需要使用sleep实现休眠操作,否则程序会一直连续的打印内容
再来一个测试脚本
if判断
前面我们学习了两个循环的使用,下面来学习一下if这个逻辑判断,有了if,shell脚本才真正有了灵魂
多条件分支案例
shell扩展
在实际工作中会遇到这种情况,针对带有while无限循环的shell脚本,我们希望它能够一直运行,不影响我在这个窗口执行其它操作
但是现在它会一直占用这个shell窗口,我们称这个脚本现在是在前台执行,不想让它一直占用shell窗口的话,需要把它放到后台执行,如何放到后台呢?很简单,在脚本后面添加一个&即可
演示一下,这样就可以了
如何保证关闭shell窗口而不影响放到后台的shell脚本执行呢?
也很简单,在命令前面加上nohup 即可
原理就是,默认情况下,当我们关闭shell窗口时,shell窗口会向之前通过它启动的所有shell
脚本发送停止信号,当我们加上nohup之后,就会阻断这个停止信号的发送,所以已经放到后台的shell脚本就不会停止了。
最后来看一个综合案例
nohup hello.sh >/dev/null 2>&1 &
我们来解释一下
nohup和&:可以让程序一直在后台运行
/dev/null:是linux中的黑洞,任何数据扔进去都找不到了
>/dev/null:把标准输出重定向到黑洞中,表示脚本的输出信息不需要存储
2>&1 :表示是把标准错误输出重定向到标准输出中