shell脚本
一:shell脚本的概念
1:自动化系统初始化(update,软件安装,时区设置,安全策略)
2:自动化批量软件部署程序(lnmp,llamp,nginx)
3:管理应用程序(kvm,集群管理扩容,mysql)
4:日志的分析处理程序
二:shell脚本的变量
1:变量的命名规则
1)命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
2)等号的左右2边,不能有空格,可以使用下划线,变量的值如果有空格的话,可以使用双引号包括,里面的$号,转义可以使用
但是单引号的话,里面内容全是普通字符
3)环境变量建议大写,比较好区分
4)如果需要增加变量的值,可以进行变量值的增加,
第一种:"$name 变量名"
第二种:${name}dasdasd
关于双引号和单引号的问题:
双引号能够识别变量
单引号不能识别变量,原样输出
2:shell中的特殊符号
符号 | 作用 |
' ' | 单引号,里面的所有特殊符号都没有用,都是普通字符 |
" " | 双引号,$,``,\ 拥有调用变量的值,引用命令 |
`` | 反引号,括起来的内容就是系统命令 |
$() | 和反引号作用一样,引用系统命令 |
() | 用于一串命令的执行,()中的命令会在子shell中执行(当前的shell) |
{} | 用于一串命令的执行, |
[ ] | 条件表达式,都放在这里面,-a,-o !逻辑运算,也支持字符串运算 |
[ [ ] ] | 包括了[ ],但是它支持正则表达式,|| && 都支持 |
# | 表示注释 |
$ | 用于调用变量的值 $name |
\ | 转义字符,跟在他的后面会失去原有的含义 |
3:双引号和单引号
[root@localhost ~]$ name=sc #定义变量name 的值是sc [root@localhost ~]$ echo '$name' $name #如果输出时使用单引号,则$name原封不动的输出 [root@localhost ~]$ echo "$name" sc #如果输出时使用双引号,则会输出变量name的值 sc [root@localhost ~]$ echo `date` 2018年10月21日星期一18:16:33 CST #反引号括起来的命令会正常执行 [root@localhost ~]$ echo '`date`' `date` #但是如果反引号命令被单引号括起来,那么这个命令不会执行,―date`会被当成普通字符输出 [root@localhost ~]$ echo "`date'" 2018年10月21日星期一18:14:21 CST #如果是双引号括起来,那么这个命令又会正常执行
4:反引号
引用系统的命令,相当于$()
[root@localhost ~]$ echo ls ls #如果命令不用反引号包含,命令不会执行,而是直接输出 [root@localhost ~]$ echo `ls` anaconda-ks.cfginstall.loginstall.log.syslog sh test testfile #只有用反引号包括命令,这个命令才会执行 [root@localhost ~]$ echo $(date) 2018年10月21日星期一18:25:09 CST #使用$(命令)的方式也是可以的
三:变量的分类
1:用户自定义变量
最常见的变量,有用户自由定义,在当前的shell中执行
1)变量的定义
[root@localhost ~]$ 2name="shen chao" -bash: 2name=shen chao: command not found #变量名不能用数字开头 [root@localhost ~]$ name = "shenchao" -bash: name: command not found #等号左右两侧不能有空格 [root@localhost ~]$ name=shen chao -bash: chao: command not found #变量的值如果有空格,必须用引号包含
2)变量的调用
[root@localhost ~]$ name="shen chao" #定义变量name [root@localhost ~]$ echo $name #调用变量使用 $变量名 shen chao #输出变量name的值
3)变量的查看
[root@localhost ~]$ set [选项] 选项: -u:如果设定此选项,调用未声明变量时会报错(默认无任何提示) -x:如果设定此选项,在命令执行之前,会把命令先输出一次 +<参数> :取消某个set曾启动的参数。 [root@localhost ~]$ set BASH=/bin/bash …省略部分输出… name='shen chao' #直接使用set 命令,会查询系统中所有的变量,包含用户自定义变量和环境变量 [root@localhost ~]$ set -u [root@localhost ~]$ echo $file -bash: file: unbound variable #当设置了-u选项后,如果调用没有设定的变量会有报错。默认是没有任何输出的。 [root@localhost ~]$ set -x [root@localhost ~]$ ls +ls --color=auto anaconda-ks.cfginstall.loginstall.log.syslog sh tdir testtestfile #如果设定了-x选项,会在每个命令执行之前,先把命令输出一次 [root@localhost ~]$ set +x #取消启动的x参数
4)变量的删除
[root@localhost ~]$ unset 变量名
2:环境变量
系统保存的变量,尽量不要修改,父shell,子shell都能执行
1)环境变量的设置
[root@localhost ~]$ export age="18" #使用export声明的变量即是环境变量
2)环境变量的查询和删除
env命令可以查看所有的环境变量,set可以查看所有变量
[root@localhost ~]$ unset gender #删除环境变量gender [root@localhost ~]$ env | grep gender
3:位置参数变量
主要就是橡向脚本中传递参数,变量名不能随意改变,变量的作用是固定的
$n | n为数字,$1到$9,10以上的参数用{10} |
$* | 这个变量代表命令中的所有参数,$把所有参数看成一个整体 |
$@ | 也代表所有参数,只不过是每个参数区分对待 |
$# | 命令中所有参数的个数 |
1)$1
[root@localhost sh]$ vim test.sh #!/bin/sh echo "shell脚本本身的名字: $0" echo "传给shell的第一个参数: $1" echo "传给shell的第二个参数: $2"
执行的时候 bash test.sh 1 2
2)$* $@
[root@localhost sh]$ vi parameter2.sh #!/bin/bash for i in"$*" #定义for循环,in后面有几个值,for会循环多少次,注意“$*”要用双引号括起来 #每次循环会把in后面的值赋予变量i #Shell把$*中的所有参数看成是一个整体,所以这个for循环只会循环一次 do echo "The parameters is: $i" #打印变量$i的值 done x=1 #定义变量x的值为1 for y in"$@" #同样in后面的有几个值,for循环几次,每次都把值赋予变量y #可是Shel1中把“$@”中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次 do echo "The parameter$x is: $y" #输出变量y的值 x=$(( $x +1 )) #然变量x每次循环都加1,为了输出时看的更清楚 done
$* 都看成一个整体,$@区别看待
4:预定义变量
已经定义好了的变量
$? | 证明上一次执行命令的正确性,正确返回为0,错误则不为0 |
$$ | 当前进程的pid |
$! | 后台运行的最后一个进程的pid |
1)$?
检查上一个命令是否正确的运行,为0就是正确的运行,不为0就是错误的输出
[root@localhost /]# asda bash: asda: 未找到命令... [root@localhost /]# echo $? 127 [root@localhost /]# ls 1 boot etc home lib64 mnt opt root sbin sys usr bin dev ftp-share lib media nfs-share proc run srv tmp var [root@localhost /]# echo $? 0 [root@localhost /]#
2)$$ 和 $!
[root@localhost sh]$ vi variable.sh #!/bin/bash echo "The current process is $$" #输出当前进程的PID. #这个PID就是variable.sh这个脚本执行时,生成的进程的PID find /root -name hello.sh & #使用find命令在root目录下查找hello.sh文件 echo "The last one Daemon process is $!" #输出这个后台执行命令的进程的PID,也就是输出find命令的PID号
5:read定义变量
#/biin/bash read -p "请输入你的名字:" name read -s -p "请输入你的年龄:" age echo -e "\n" #换行,不然的话,输出年龄时候,不会换行 echo "你的名字是$name, 年龄是$age" ~
与while语句搭配的使用
就是while能够以行来读取文件,在done < 文本文件 ,read 变量 这个变量就是每一行读取的文件的存储的地方
四:shell的运算符
shell语言和其他的编程脚本的语言一样,有算术运算符,逻辑运算符,字符串运算符,文件测试符等
1:算术运算符
1)expr 表达式
#加法 [root@localhost ~]# expr 3 + 4 7 [root@localhost ~]# #减法 [root@localhost ~]# expr 7 - 5 2 [root@localhost ~]# #乘法(需要转义) [root@localhost ~]# expr 6 \* 10 60 [root@localhost ~]# #除法 [root@localhost ~]# expr 9 / 3 3 [root@localhost ~]#
2)$(())运算(最常用的运算符)
里面可以不带上$,当然,特殊情况下,必须要带上
#加法 [root@localhost ~]# num1=10 [root@localhost ~]# num2=11 [root@localhost ~]# echo $((num1+num2)) 21 [root@localhost ~]# #减法 [root@localhost ~]# echo $((num1-num2)) -1 [root@localhost ~]# #乘法 [root@localhost ~]# echo $((num1*num2)) 110 [root@localhost ~]# #除法 [root@localhost ~]# echo $((num1/num2)) 0 [root@localhost ~]# l
里面还可以加上括号,改变运算的顺序
3)$[ ]运算(也是最常用的运算符)
#加法 [root@localhost ~]# num1=10 [root@localhost ~]# num2=20 [root@localhost ~]# echo $[num1+num2] 30 [root@localhost ~]# #减法 [root@localhost ~]# echo $[num1-num2] -10 [root@localhost ~]# #乘法 [root@localhost ~]# echo $[num1*num2] 200 [root@localhost ~]# #除法 [root@localhost ~]# echo $[num2/num1] 2 [root@localhost ~]#
4)let 运算
用于累加的一个运算,非常好用
i++和++i的区别 1)对变量值的影响 只是对于变量的值而言,没有任何的影响 i和j没有任何影响 2)对于表达式的影响 x=i++ 先赋值在运算,x=i,i++ y=++i 先运算在赋值, 输出的结果为 x=1 ,y=2 ,但是i和j的值都为2 这就是区别
2:关系运算符
关系运算符,支持数字之间的比较,谁大谁小
运算符 | 单词 | 说明 | 举列 |
-eq | equal | 检测2个数是否相等,相等返回true | [ $a -eq $b ],返回flase |
-ne | not equal | 检测2数是否相等,不相等返回flase | |
-gt | great than | 检测左边的数是否大于右边的,返回true | |
-lt | less than | 检测左边的数是否小于右边的,返回true | |
-ge | great than or equal | 检测左边的数是否大于等于右边,返回为true | |
-le | less than or equal | 检测左边的数是否小于等于右边的数,返回true |
题目:检查用户是否存在,如果存在就提示用户存在,不存在就提示用户不存在
read -p "请输出要查询的用户名:" username count=`cat /etc/passwd | grep $username | wc -l` if [ $count -eq 0 ];then echo "$username 不存在" else echo "$username 存在" fi
#思路就是通过输入的用户,在用户的配置文件中去找寻该用户并统计行数,如果为0就证明没有该用户
3:逻辑运算符
运算符 | 说明 | 举列 |
! | 非运算,表达式为true,则返回flase,否则返回true | |
-o | 或运算,有一个表达式为true,就返回true | [ $a -lt 20 -o -gt 100 ],返回true 这个数小于20有大于100,有一个真,返回true |
-a | 与运算,2个都为true,才返回true |
或运算:有一个为真,就是真
与运算:有一个为假,就是假
4:字符串运算符
[ ] 基本上比较都是放在了 中括号里面的
== | 检测2个字符是否相等,返回true | |
!= | 检测2个字符是否相等,不相等返回true | |
-z | 检测字符串的长度是否为0,为0返回true | |
-n | 检测字符串的长度是否为0,不为0返回true | |
str | 检测字符串是否为空,不为空返回true | |
5:文件测试符
-b file | 检测文件是否是块文件,是的话,返回true | |
-c file | 检测文件是否是字符设备 | |
-d file | 检测文件是否为目录 | |
-f | 检测文件是为文件 | |
-w | 检测文件是否为可写 | |
-e | 检测文件(包括目录)是否存在 | |
-s | 检查文件是否为空 |
6:正则表达式
[ [ ] ] | 条件判断语句,支持&&和正则表达式 |
=~ | 正则匹百配,判断左边是否等于右边 |
^ | 以什么开头 |
^[0-9] | 以数字开头 |
^[0-9]+ | 以数字开头,且数字有1到多个 |
$ | 以什么结尾 |
^[0-9]+$ | 以1到多个数字开头切且结尾 |
总结性的话语,就是比较数值,判断什么样的条件,可以用 [ ],这个能解决大部分的问题,(())也可用,就是符号是数字类型的
五:流程控制
一:if语句
格式
if 条件判断;then 代码 elif 条件判断;then else 代码 fi
用于来判断的
二:case语句(if的升级版)
格式:
case 变量 in 条件) 代码 ;; *) 代码 ;; esac
2个语句都能做关于分数的判断的问题
三:for语句
for in循环的语法格式为:for 变量名 in 列表;do 命令;做 列表可以是一个字符串、一个文件名或者一个命令的输出结果 如果列表是一个字符串,那么for循环会将字符串按照空格分割成多个元素,然后依次遍历每个元素 如果列表是一个文件名,那么for循环会读取文件的每一行作为一个元素,然后依次遍历每个元素 如果列表是一个命令的输出结果,那么for循环会将命令的输出结果按照空格分割成多个元素,然后依次遍历每个元素 在for循环中,变量名可以是任意合法的变量名,但建议使用有意义的变量名,以便于代码的可读性和维护性
格式:
for i in 变量 do 代码 done
这个是原始的,变量可以是文本
还有另外的一个格式:
for ((初值;条件;步长)) do 代码 done
利用for来完成指定用户的批量创建
四:while语句
条件必须返回为真才能进行循环,
格式:
while 条件 do 代码 done echo
语法格式一: while [条件] do 操作 done 语法格式二: while read line do 操作 done < file 通过read命令每次读取一行文件,文件内容有多少行,while循环多少次
六:shell的总结
1:关于符号的总结
1)[ ] [ [ ] ]
[ ]和[ [ ] ] 2个方括号,可以适用于大部分的运算,唯一的不同就是双括号支持正则表达式,和逻辑运算符,&& ||
基本上双括号的功能包括单括号
那就介绍一下 [ ]
支持关系运算符,不能是 > < ,只能是 le lt ge gt eq ne 这些关系运算符,支持逻辑运算符, -a ,-o !
字符的运算也支持, -d -f 等
2) ()(())
支持关系运算符,> < = 逻辑运算符也支持 -a -o ! && ||
2:语句的总结
for语句和while语句
for语句是以空格来读取文件的,遇见空格就要执行,可以改变分割符 IFS='
'
while语句是以行来读取文件,分割符为空格或者tab
所以在处理文件上面的操作的话,使用while语句比较好