Linux自动化运维工程师
实验所用系统为Redhat-rhel8.2。
实验环境:
一台配置好网络软件仓库和IP的虚拟机
Linux自动化运维工程师–shell的执行流控制
执行流是在脚本中记录的命令执行的顺序,有从上到下依次执行,循环,选择等等。
一、for语句
1、作用
为循环执行动作
2、结构
for 定义变量
do 使用变量,执行动作
done 结束标志
3、基本格式
1)用命令的执行结果赋值for变量
for NUM in `seq 1 10` ##``表示先执行此命令,将命令执行结果赋值给for变量
do
echo $NUM
done

2)列表方式,有多少个变量,任务重复多少次
for NAME in westos lee root test
do
id $NAME &> /dev/null && {
echo $NAME is exist
} || {
echo $NAME is not exist
}
sleep 1 ##使for语句1秒钟循环一次
done

3)连续选择,也可以是倒序选择
for WESTOS in {1..10} ##1-10连续选择,也可以是10-1的倒序选择
do
echo $WESTOS
done

4)范围内自加或自减
for ((WESTOS=0;WESTOS<10;WESTOS++))
do
echo $WESTOS
done

- 练习1: 编写脚本check_host.sh,用此脚本检测10台与您当前主机直连主机是否网络通常,如果网络通常请显示主机的ip列表。
- 思路解析:首先这是一个连续数字的选择,可以选择第一种格式,也可以选择第三种格式,在1-10之间逐个拿出数字放入IP中进行网络连接。如果连通显示up,不能则显示down。
for HOST in {1..10}
do
ping -c1 -w1 172.25.254.$HOST &> /dev/null && {
echo 172.25.254.$HOST is up
} || {
echo 172.25.254.$HOST is down
}
done


- 练习2:编写脚本user_list.sh,用此脚本检测用户列表中的用户是否存在。如果后面没有文件则报错,文件不存在则报错。如果列表中的用户存在,则显示存在;不存在则建立。
[ -z "$1" ] && { ##判断是否有跟文件
echo "Error: Plesae input filename !" ##没有则报错退出
exit
}
[ -e "$1" ] || { ##判断文件是否存在
echo "Errot: $1 is not exist !" ##不存在则报错退出
exit
}
[ "$USER" != "root" ] && { ##判断当前用户是否为超级用户,因为只有超级用户可以建立用户
echo "Error: Please run script with root !"
exit
}
for USER in `cat $1` ##查看指定文件中的用户
do
id $USER &> /dev/null && { ##检测用户是否存在
echo $USER is exist !
} || {
useradd $USER &> /dev/null && { ##不存在则建立用户
echo $USER is created!
}
}
done




二、条件语句
1、while…do语句
1)作用
条件为真执行动作
2)语句结构
while ture <!--条件为真-->
do <!--条件成立所作循环动作-->
done <!--结束-->
示例:
while true
do
read -p "Please input word : " WORD
echo $WORD
done


2、until…do 语句
1)作用
条件为假执行动作
2)语句结构
until false <!--条件为假-->
do <!--条件不成立所作循环动作-->
done <!--结束-->
示例:
until false
do
read -p "Please input word : " WORD
echo $WORD
done


3、if…then…elif…then…else…fi 语句
1)作用:
多次判定条件执行动作
2)语句结构
if <!--首次判断定-->
then <!--条件成立执行动作-->
elif <!--当首次判定不成立时再次判定-->
then <!--条件成立执行动作-->
... <!--elif可以书写多次-->
else <!--所有条件不成立执行动作-->
fi <!--结束-->
- 练习3: 编写脚本check_file.sh,首先输出please input filename: 提示需要输入文件名称。然后判断文件是否存在。如果不存在,报错file is not exist;如果存在,则判断文件类型,是文件则输出file is file,是目录则输出file is direcory等等。此脚本会一直询问直到用户输入exit为止。
while true
do
read -p "Please input filename: " FILENAME ##提示输入文件名称
if [ "$FILENAME" = "exit" -o "$FILENAME" = "EXIT" ] ##判断是否输入为退出标识“exit”
then
exit
elif [ ! -e "$FILENAME" ] ##不是则判断文件是否存在
then
echo "Error: $FILENAME is not exist !" ##不存在则报错退出
elif [ -L "$FILENAME" ] ##存在则判断文件类型
then
echo "$FILENAME is a link file" ##是否为链接
elif [ -f "$FILENAME" ]
then
echo "$FILENAME is a common file" ##是否为文件
elif [ -d "$FILENAME" ]
then
echo "$FILENAME is a directory" ##是否为目录
elif [ -S "$FILENAME" ]
then
echo "$FILENAME is a socket" ##是否为套接字
elif [ -b "$FILENAME" ]
then
echo "$FILENAME is a block file" ##是否为块设备
elif [ -c "$FILENAME" ]
then
echo "$FILENAME is a char file" ##是否在字符设备
fi
done


三、case
在对于信息选择过程中,因为判定语句选择信息需要判定从开始到正确的信息,效率很低。可以使用选择语句,在对于选择信息判定时具有平等的执行过程,所以对于选择条件的执行只需要判定一次。
格式:
case $1 in
word1|WORD1)
action1
;;
word2|WORD2)
action2
;;
*)
action3
esac
实验:编写同样判定内容的两个脚本,一个使用if…then…fi语句,一个使用case语句,观察其执行过程。
- if…then…fi语句
if [ "$1" = "linux" ] ##输入linux
then
echo westos ##输出westos
elif [ "$1" = "westos" ] ##输入westos
then
echo redhat ##输出redhat
elif [ "$1" = "redhat" ] ##输入redhat
then
echo linux ##输出linux
else
echo error ##输入其他内容则报错
fi

观察其执行过程,不论输入什么,程序都是从第一个判断条件开始判断。

- case语句
case $1 in
linux)
echo westos
;;
westos)
echo redhat
;;
redhat)
echo linux
;;
*)
echo error
esac

观察其执行过程,程序会根据输入选择判定,每一次都只需要执行两步。

因此,判定语句选择信息需要判定从开始到正确的信息,效率很低;使用选择语句,在对于选择信息判定时具有平等的执行过程,所以对于选择条件的执行只需要判定一次。
- 练习4:编写脚本user_ctrl.sh,使用case语句,输入用户名,选择添加用户或者删除用户。
case $1 in
add) ##如果输入添加
read -p "Please input username: " USERNAME ##提示输入用户名称
id $USERNAME &> /dev/null && { ##判断用户是否存在
echo $USERNAME is exist ##存在则显示已存在
}
useradd $USERNAME &> /dev/null && { ##不存杂则建立该用户
echo $USERNAME is created ##显示已建立
}
;;
del) ##如果输入删除
read -p "Please input username: " USERNAME
id $USERNAME &> /dev/null || {
echo $USERNAME is not exist
}
userdel -r $USERNAME &> /dev/null && {
echo $USERNAME is deleted
}
;;
*) ##如果输入其他则报错
echo error
esac


- 练习5:编写脚本ctrl_user.sh,要求如下:

USER_CTRL() ##定义一个函数用于用户控制
{
read -p "Please input username: " USER
if [ "$USER" = "exit" ] ##判定用户名称是否为exit
then
break ##跳出该动作
else
id $USER &> /dev/null && { ##判定用户是否存在,存在的情况下
case $1 in
add) ##添加则显示已存在
echo "$USER is exist !"
USER_CTRL
;;
del) ##删除则删除用户
userdel -r $USER
echo $USER is deleted
USER_CTRL del
esac
} || { ##不存在的情况下
case $1 in
add) ##添加用户切设定密码
read -p "Please input password: " -s PASSWD
useradd $USER
echo $PASSWD | passwd --stdin $USER &> /dev/null
echo " "
echo $USER is created
USER_CTRL add
;;
del) ##删除则提示用户不存在
echo "$USER is not exist !"
USER_CTRL del
esac
}
fi
}
while true
do
read -p "Please input action: " ACTION ##提示动作
case $ACTION in
exit) ##exit则退出脚本
exit
;;
add) ##add则调用函数add
USER_CTRL add
;;
del) ##del则调用函数del
USER_CTRL del
;;
*) ##其他则报错
echo wrong action
esac
done

四、expect
有很多时候我们需要交互式执行动作,但此前我们学习的命令并不能做到交互式自动应答。
首先我们编辑一个问题脚本并且个执行权限。
vim ask.sh
///
#!/bin/bash
read -p "what's your name:" NAME
read -p "How old are you: " AGE
read -p "Which objective: " OBJ
read -p "Are you happy? " FEEL
echo $NAME is $AGE\'s old study $OBJ feel $FEEL
///
chmod +x ask.sh
然后执行脚本,回答问题。

但是,此类脚本不能自动应答。可以编辑一个回答脚本,使用输入重定向。
vim answer.sh
///
/mnt/ask.sh <<EOF
yun
1
linux
happy
EOF
///
执行该脚本。

此时可以自动应答,但是因为有些问题不是每次都会出现,所以此方式在应对交互问题时非常机械,不能判定问题的准确性。
比如,我们注释掉一个问题,最后的回答就会是错误的。


因为此类方式回答是按照顺序的,与问题内容并不对应,十分机械。
我们就需要要一个可以自动应答的脚本,首先安装自动应答器。
dnf install expect -y ##自动应答器
编辑一个自动应答脚本。
vim answer1.exp
///
#!/usr/bin/expect ##运行环境
spawn /mnt/ask.sh ##监控该问题文件
expect "name"
send "yun\r"
expect "old"
send "1\r"
expect "objective"
send "linux\r"
expect "happy"
send "happy\r"
expect eof ##问题回答完毕后退出expect 两个参数选一个
interact ##问题回答完毕后保留expect环境 两个参数选一个,不可以都写
///
再来执行此脚本,应答是正确的。

但如果此时将一条问题注释掉,回答的问题依旧是错误的,是因为此时的answer是用多个expect做应答,每一个expext只监控自己的问题。

但如果需要监控某个问题是否出现,则可以使用一个expect应答所有问题。
vim answer.exp
///
#!/usr/bin/expect
spawn /mnt/ask.sh
expect {
"name" { send "yun\r";exp_continue }
"old" { send "1\r";exp_continue }
"objective" { send "linux\r";exp_continue }
"happy" { send "happy\r" } ##最后一个问题必须存在,问题的顺序没有要求
}
expect eof
///
此时再执行注释掉一条问题的脚本,回答便不会错乱。
但此时因为我们将答案写入了脚本里,无法控制答案也无法更改,还是很机械,所以我们需要用函数来代替固定的答案。
vim answer2.exp
///
#!/usr/bin/expect
set timeoout 1 ##超时时间为1s
set NAME [ lindex $argv 0 ] ##脚本后所跟的第一串字符,定义其值为NAME
set AGE [ lindex $argv 1 ]
set OBJ [ lindex $argv 2 ]
set FEEL [ lindex $argv 3 ]
spawn /mnt/ask.sh
expect {
"name" { send "$NAME\r";exp_continue }
"old" { send "$AGE\r";exp_continue }
"objective" { send "$OBJ\r";exp_continue }
"happy" { send "$FEEL\r" }
}
expect eof
///
此时执行脚本,如果不输入内容,问题则没有答案。

- 练习6:编写脚本check_host.sh 后面加上IP172.25.254.1,当1是通的,显示主机名,不通则显示down。
vim check_host1.sh
///
[ -z "$1" ] && { ##判定是否加IP,此处的$1表示执行sh命令时所跟的第一串字符
echo "Please input ipaddress following script ! "
exit
}
Auto_Ssh()
{
/usr/bin/expect <<EOF ##在此环境下执行
spawn ssh -l root $1 hostname ##连接此IP,并查询主机名,此处的$1 表示函数Auto_Ssh后所跟的第一串字符
expect {
"yes/no" { send "yes\r";exp_continue } ##连接时需要输入yes/no
"password" { send "westos\r" } ##需要输入此主机的密码
}
expect eof
EOF
}
ping -c1 -w1 $1 &> /dev/null && { ##ping该主机
Auto_Ssh $1 | tail -n 1 ##通了则调用函数
} || {
echo $1 is down ##不通则显示down
}
///

五、执行流控制器
1、循环控制
contiue ##终止当此次前循环提前进入下个循环
break ##终止当前所在语句所有动作进行语句外的其他动作
exit ##脚本退出,exit退出值可以指定
示例:
1-10循环设定4为幸运数字,其他数字则显示其自身。(我把luck打错了,写博客时才发现,biao笑……)
vim text.sh
///
for N in {1..10}
do
if [ "$N" -eq "4" ]
then
echo luch number
fi
echo $N
done
echo westos linux
///
此时每个数字都显示,并且luck number显示在数字4上面。

当显示4为幸运数字后,continue提前终止此次循环。此时数字4因为循环终止,是不会显示的。

当显示4为幸运数字后,break终止当前所在的循环语句。则此后的所有数字都不会显示,但循环外的进程仍然会被执行。

当显示4为幸运数字后,exit结束当前脚本所有进程,则从当前开始结束所有进程。

2、退出值
$? ##表示退出值
退出值为0 ##表示命令无报错
退出值非0 ##表示命令有相应报错
exit可以指定退出值,范围是0~255。


[注意] 退出值范围为0~255,如果超出,退出值为对256取余。
Linux自动化运维工程师–shell中的运算
一、运算符号
| 符号 | 意义 |
|---|---|
| + | 加法 |
| - | 减法 |
| * | 乘法 |
| / | 除法 |
| % | 取余,除法后的余数 |
| ** | 乘方 |
| ++ | 自加一 |
| – | 自减一 |
| < | 小于 |
| <= | 小于等于 |
| > | 大于 |
| >= | 大于等于 |
| += | (j+=i) j=j+i |
| *= | (j*=i) j=j*i |
| /= | (j/=i) j=j/i |
| %= | (j%=i) j=j%i |
二、运算指令
| 指令 | 用法示范 | 限制 |
|---|---|---|
| (()) | ((a=1+2)) | 只能算整数 |
| let | let a=1+2 | 只能算整数 |
| expr | expr 1 + 2 (注意空格) | 只能算整数 |
| bc | bc << EOF \n 1+2 \n EOF | 可以算小数 |
| $[ ] | echo $[1+2] | 只能算整数 |
示例:


-
自加一


-
自减一

-
j=j+i

三、小数表示方法
printf '%0.2f' .3 ==== 0.30 ##小数点后两位
printf '%0.3f' .3 ====0.300 ##小数点后三位
printf '%0.4f' .3 ====0.3000

本文详细介绍了Linux自动化运维中Shell脚本的执行流控制,包括for、while、until、if...then...fi、case等语句的用法,并通过实例演示了网络检测、用户管理等实际应用。此外,还讲解了条件判断、循环控制、Exit值以及Shell中的运算操作,如加减乘除、自增自减等。同时,提供了多个实战练习,帮助读者巩固理解。
1015

被折叠的 条评论
为什么被折叠?



