Shell脚本基础
一、shell脚本
1、Shell作用
Linux 系统中的 Shell 是一个特殊的应用程序,它介于操作系统内核与用户之间,充当 了一个“命令解释器”的角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执 行的操作传递给内核执行,并输出执行结果
cat /etc/shells可以查看当前系统支持的shell
2、shell构成
·注释信息:以#开头的语句表示为注释信息
·可执行语句:比如echo命令用于输出“ ”之间的字符串
3、linux中常见的shell
-
bash:基于gun的框架下发展的shell
-
csh:类似c语言的shell
-
tcsh:整合了csh提供了更多功能
-
sh:已经被bash替换
-
#!/bin/bash
ehco “hello world”
4、脚本执行逻辑
顺序执行:程序按从上到下顺序执行
循环执行:程序执行过程中需要重复执行多次某段语句
5、执行方式
指定路径去执行文件(需要有执行权限)
chmod +x /root/host.sh 加权限
指定相对路径./host.sh
指定绝对路径/root/host.sh
使用.执行脚本 . host.sh
使用source执行脚本 source host.sh
6、脚本错误测试
命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察
二、变量
` `和 $() | 调用命令执行结果 |
' ' | 强引用,不识别变量本来含义 |
" " | 弱引用,识别变量 |
{ } | 确定变量的范围 |
1、变量赋值和引用变量 a=3 echo $a a="www.junmajinlong.com" echo $a a='hello world' echo $a
Shell中可以引用未定义的变量: echo $xyzdefabc
可以定义空变量: a= echo $a
2、变量替换 变量替换是指在命令开始执行前,Shell会先将变量的值替换到引用变量的位置处。 a="hello" echo $a world
在echo命令开始执行前,Shell会取得变量a的值hello,并将它替换到命令行的$a处。于是,在echo命令开始执行时,命令行已经变成: echo hello world
除了变量替换,Shell还会做其它替换: 命令替换 进程替换 算术运算替换 大括号扩展 波浪号扩展 路径扩展 这些扩展和替换,都是Shell在调用命令之前就完成的,这和其它语言解析代码的方式不一样。 3、命令替换 使用反引号或$()可以执行命令替换。 `cmd` $(cmd) 命令替换是指先执行cmd,将cmd的输出结果替换到$()或反引号位置处。 例如: echo `id root` echo $(id root) 在echo命令执行前,会先执行id命令,id命令的执行结果: $ id root uid=0(root) gid=0(root) groups=0(root) 所以会将结果uid=0(root) gid=0(root) groups=0(root)替换$(id root)。于是,echo命令开始执行时,命令行已经变成了: echo uid=0(root) gid=0(root) groups=0(root)
4、算术运算 $[]或$(())或let命令可以做算术运算。 let是单独的命令,不能写在其它命令行中。 a=3 let a=a+1 echo $a $[]和$(())可以写在命令行内部,Shell在解析命令行的时候,会对它们做算术运算,然后将运算结果替换到命令行中。 a=33 echo $[a+3] echo $((a+3)) 因为变量替换先于算术替换,所以,使用变量名或引用变量的方式都可以: a=333 echo $[$a+3] echo $(($a+3))
5、退出状态码 每个命令执行后都会有对应的进程退出状态码,用来表示该进程是否是正常退出。 所以,在命令行中,在Shell脚本中,经常会使用特殊变量$?判断最近一个前台命令是否正常退出。 通常情况下,如果$?的值: 为0,表示进程成功执行,即正常退出 非0,表示进程未成功执行,即非正常退出 但非0退出状态码并不一定表示错误,也可能是正常逻辑的退出 另外,在Shell脚本中,所有条件判断(比如if语句、while语句)都以0退出状态码表示True,以非0退出状态码为False。
预定义变量
$@ | 返回所有当成个体 |
$* | 返回所有当初整体 |
$# | 参数的总个数 |
$$ | 当前bash 的uid |
$0 | 当前脚本名字 |
$? | 上一次执行命令结果,0正确,非0不正确 |
三、测试
1、test 测试文件的表达式 是否成立
操作符:
-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-a:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否有权限执行(eXcute)
-L: 测试是否为软连接文件
若真,则状态码变量 $? 返回0
若假,则状态码变量 $? 返回1
2、比较整数数值
[ 整数1 操作符 整数2 ] 公式
-
-eq:第一个数等于(Equal)第二个数
-
-ne:第一个数不等于(Not Equal)第二个数
-
-gt:第一个数大于(Greater Than)第二个数
-
-lt:第一个数小于(Lesser Than)第二个数
-
-le:第一个数小于或等于(Lesser or Equal)第二个数
-
-ge:第一个数大于或等于(Greater or Equal)第二个数
3、逻辑测试
&&运算符:
命令之间使用 && 连接,实现逻辑与的功能。
只有在 && 左边的命令返回真(命令返回值 $? == 0),&& 右边的命令才会被执行。
只要有一个命令返回假(命令返回值 $? == 1),后面的命令就不会被执行。
示例中,cp命令首先从root的家目录复制文件文件anaconda-ks.cfg到 /data目录下;执行成功后,使用 rm 命令删除源文件;如果删除成功则输出提示信息"SUCCESS"。
||运算符:
命令之间使用 || 连接,实现逻辑或的功能。
只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作。
只要有一个命令返回真(命令返回值 $? == 0),后面的命令就不会被执行。
示例中,如果 dir目录不存在,将输出提示信息 fail 。
()和{ }运算符:
(CMD1;CMD2;...)和 {空格CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行
( ) 表示在当前 shell 中将多个命令作为一个整体执行。
如果使用{ }来代替( ),那么相应的命令将在子shell而不是当前shell中作为一个整体被执行,只有在{}中所有命令的输出作为一个整体被重定向时,其中的命令才被放到子shell中执行,否则在当前shell执行。