Linux自动化运维工程师--(4)shell的执行流控制与运算

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

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))只能算整数
letlet a=1+2只能算整数
exprexpr 1 + 2 (注意空格)只能算整数
bcbc << 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

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值