RHEL之(八)Red Hat Linux Shell编程基础 V :脚本任务控制(下)
6:循环语句--for循环
(1)语法
for <变量> in <项目列表>;
do
<命令> <命令>迭代<变量>的值 ……
done
(2)for i in的各种用法
for i in "file1" "file2" "file3" ##读取列表中的值
for i in /boot/* ##使用通配符读取目录
for i in /etc/*.conf ##使用通配符读取文件
for i in $(seq -w 10) ##等宽的1-10
for i in {1..10} ##范围
for i in ${ ls } ##从命令读取值
for i in $(< file) ##从文件里面读取内容for i in "$@" ##取所有位置参数,可以简写为for i
$@:所有位置变量的内容
$#:位置变量的个数
$0:文件名
$1 $2:文件后面的第一个/第二个参数
$*:所有位置变量的内容(类似$@)
(3)for循环写法:
A.C语言风格
for((i=1;i<=100;i++)) //注:两个括号
do
echo $i
done
B.python风格
for i in {1..100} //注:花括号
do
echo $i
done
c. seq的使用
for i in `seq 1 100` //注:以命令的形式声明范围
do
echo $i
done
7:while循环
(1)定义:if-then和for循环的结合体
当rc(return code)=0,继续执行迭代;
当rc!=0,停止执行。
(2)格式:
while [ test command ]; ##可以使用任何普通的Bash Shell命令或者用test命令进行条件测试
do
other commands
done
例子:降序输出10以内的自然数


(3)多个测试命令:while命令允许在while语句行中定义多个测试命令,只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。


Tips:
gt (greater than)=大于
lt (less than)=小于
ge (greater equal)=大于等于
le (less equal)=小于等于
eq (equal)=等于
ne (not equal)=不等于
8:until
(1)定义:跟while的工作方式完全相反
当rc=0,退出; 当rc!=0,继续执行。
(2)语法:
until [ test command ];
Do
other commands
done


(3)和while类似,也可以在until命令语句中放入多个测试命令,只有最后一个命令的退出状态码决定了Bash Shell是否执行已定义的other commands。

Tips:
while满足条件就循环,直到条件不满足后退出循环
until不满足条件就循环,直到条件满足后退出循环
9:条件循环结构if
(1)定义
条件结构允许用户在shell脚本中包含决策,以便仅当满足特定条件时才执行脚本的特定部分。有一类命令会根据条件时脚本跳过某些命令,这样的命令称为结构化命令(structured command),结构化命令允许你改变程序执行的顺序。
(2)语法
Bash中最简单的条件结构是if/then,语法如下:
if <condition>; then
<statement>
….
<statement>
fi
if command; then
commands
fi
如果满足给定条件,将采取一个或多个操作,如果不满足给定条件,则不采取任何操作,之前的数值比较,字符串比较,和文件测试经常用于if/then语句中测试条件。
需要强调的是,其他编程语言中,if语句之后的对象是一个等式,这个等式的求值结果为true or false,但bash shell的if语句会运行if后面的那个命令,如果该命令的退出状态码是0(命令成功运行),位于then后面的命令就会被执行,如果该命令的退出状态码是其他值,then后面的部分就不会被执行,bash shell会继续执行脚本中的下一个命令,fi语句用来表示if-then语句的结束。



运行if语句中的那个错误命令所生成的错误信息依然会显示在脚本的输出中。在then部分,可以像在脚本中的其他地方一样列出多条命令,bash shell会将这些命令当做一个块,如果if语句行的命令的退出状态值为0,所有的命令都会被执行,如果if语句行的命令的退出状态不为0,所有的命令都会被跳过。

例子1:判断输入的数字是否为纯数字

Tips:
grep -q用于if逻辑判断
-q 参数,本意是 Quiet; 中文意思为安静模式,不打印任何标准输出。如果有匹配的内容则立即返回状态值0。
例子2:判断一个用户是否在系统中存在


grep后加-q后,就没有了中间user10在/etc/passwd中的一行了
有时我们需要检查脚本代码中的多种条件,就可以使用嵌套if-then语句,在满足某个条件时执行不同的操作集合。
if <condition>/command;then
<statement>
…..
elif <condition>/command; then
<statement>
…..
else
<statement>
…..
fi
例子:


可以继续将多个elif语句串起来,形成一个大的if-then-elif嵌套组合
if command1;then
command set 1
elif command2;then
command set 2
elif command3;then
command set 3
elif …
fi
每块命令都会根据命令是否返回退出状态码为0来执行,bash shell会依次执行if语句,只有第一个返回退出状态码0的语句中的then部分会被执行。但是添加的子句越多,语句及其逻辑就变得更加难以阅读和理解。所以可以使用另一个判断的语句case
10:多重分支case命令
有了case命令,就不需要再写出所有的elif语句来不停检查同一个变量的值了,case命令会采用列表格式来检查单个变量的多个值。
case命令会将指定的变量与不同模式进行比较,如果变量和模式匹配,那么shell会执行为该模式指定的命令,可以通过竖线操作在一行中分隔出多个模式,星号*会捕获所有与已知模式不匹配的值。
格式:
case $variable in
pattern1|pattern2)
command1
;; (两个分号)
pattern3)
command2
;;
pattern4)
command3
;;
*)
default commands
;; (当前面的条件都不满足时,执行这条)
esac (结尾)
case语句尝试按顺序逐个将variable和每个pattern进行匹配,当某个模式匹配时,将执行与该模式相关联的代码段。
以;;语法指示块结束,然后将跳过case语句中其余的所有其他模式,并且以esac语句退出,可以根据需要添加任意数量的模式和语句块。
11:跳出循环break
break语句用于终止整个循环的执行,完成后所有行代码break语句的执行。然后,它逐级的代码跟在循环结束。break命令用于跳出循环体,使用break可以跳出任何类型的循环:for、while、until
exit是直接退出脚本。

(1)跳出单循环

(2)跳出内循环


显然,break只跳出了内层循环。外层循环依然执行了5次。
(3)跳出多层循环
有时需要跳出多层循环,使用:break n
n表示要跳出的循环层数,默认情况下 n=1,代表只跳出当前循环。


12:continue语句
continue语句与break命令类似,但它会导致当前迭代的循环退出,而不是整个循环。这种参数是有用的,当一个错误已经发生,但你想尝试执行下一个循环迭代。
continue命令用于中止本次循环(continue后面的循坏内部语句不再执行),重新判断循环条件,开始下一次循环。
语法:
continue和break语句一样,一个整数参数可以给continue命令跳过嵌套循环的命令。
continue n //这里n指定第n个封闭循环continue



4. Bash Shell脚本错误故障排除
(1)错误通常是由于输入错误,语法错误或者脚本逻辑不佳导致。

(2)调试模式和详细模式
-vn : 开启详细模式,可以进行语法检查


Tips:用sh和bash都可以,因为sh是bash的软链接!

可以仅仅对脚本的某个部分而非整个脚本局部启用调试模式,使用set -x和set +x以分别在脚本中的特定位置开启和关闭调试。


(3)-v:详细模式,在每个命令执行前将每个命令打印到标准输出

随堂练习:
1.用shell脚本列出从2-50,等差为4的数列;


2.用shell脚本列出kernel有关的安装包的安装日期,格式如下:
kernel-4.18.0-80.el8.x86_64 was install on Tue Jul 7 10:38:00 CST 2020
Tips:rpm -qi


3.创建一个shell脚本,实现以下功能:
(1)实现对 /etc/sysconfig 目录采用 bzip2 格式进行自动打包备份
(2)保存的文件位置为:/usr/local/backup,文件命名规则为:sysconfig_bak_当前日期.tar.bz2
(3)只保留最近7天的文件备份
Tips:tar打包方式 -z gzip -j bzip2 -J xz
find -mtime +7(找到7天之前的) -exec rm -rf {} \;(记得加上)
花括号代表前面查询出来的结果

执行结果:



4. 在 servera 上创建一个名为 /root/linux.sh 的脚本,让其提供下列特性:
a. 当运行/root/linux.sh redhat ,输出为 centos ;
b. 当运行/root/linux.sh centos ,输出为 redhat ;
c. 当没有任何参数或者参数不是 redhat 或者 centos 时,其错误输出产生以下的信息:/root/linux.sh redhat|centos 。

