RHCE的学习(22)

第四章 流程控制之条件判断

条件判断语句是一种最简单的流程控制语句。该语句使得程序根据不同的条件来执行不同的程序分支。本节将介绍Shell程序设计中的简单的条件判断语句。

if语句语法

单分支结构

# 语法1:
if <条件表达式>
then
    指令
fi

#语法2:
if <条件表达式>;then
    指令
fi

双分支结构

if <条件表达式>
then
    指令序列1
else
    指令序列2
fi


if id username;then
	echo ""
else
	echo " cunzai"
fi

多分支结构

语法:
if 条件表达式1;then
    命令序列1
elif 条件表达式2;then
    命令序列2
....
else
    命令序列n
fi

案例

  • 例1:编写脚本choice1.sh,利用单分支结构实现输入2个整数,输出最大值

    [root@server ~]# vim choice1.sh

    #!/bin/bash

    read -p "请输入第一个整数: " x

    read -p "请输入第二个整数: " y

    max=x ​ if ((max<y))
    then
    max=y fi ​ echo "最大值:max"

  • 例2:面试题,编写脚本choice2.sh,判断系统内存剩余容量大小,若低于100M则发送消息进行告警

    #!/bin/bash

    free_mem=( free -m | grep Mem | tr -s " " | cut -d " " -f4 ) ​ if ((free_mem<100))
    then
    echo "警告,剩余内存:free_mem ,低于警戒线100MB" else echo "剩余内存:free_mem,空间足够."
    fi

    free -m :表示显示内存即虚拟内存的信息,-m以MB单位显示数字

    grep Mem:表示过滤包含Mem所在行

    tr -s " ": 压缩空格为一个

    cut -d " " -f4 :以空格为间隔符,取其第4部分

  • 扩展:编写脚本,判断当前系统剩余内存大小,如果低于100M,邮件报警管理员,使用计划任务,每10分钟检查一次。

  [root@locaklhost ~]# echo "邮件正文"  | mail -s "邮件主题" alice 

分析:核心是如何获取当前剩余内存大小
[root@localhost ~]# free -m | grep "Mem:" |tr -s " " | cut -d" " -f4
600
[root@localhost ~]# free -m | awk '/Mem:/ {print $4}'
600
vim mem.sh
mem=free -m |grep Mem | tr -s " " | cut -d " " -f 4
free -m | grep Mem | awk -F " " '{print }'
if   test $mem \< 100  ;then
	echo 内存严重不足 | mail -s 内存报警 lxx@163.com
else
	echo 内存足够
fi
  • 例3:编写脚本choice3.sh,判断当前脚本的执行者,若不是root账户则提示,并退出

    检查当前账户的4种方法

    [root@server ~]# whoami
    root

    #使用环境变量
    [root@server ~]# echo $USER
    root

    #id -u,结果为零则为root
    [root@server ~]# id -u
    0

    [root@server ~]# echo $UID
    0

    [root@server ~]# vim choice3.sh
    #!/bin/bash

    if [ "USER" != "root" ] #或者if [ !c_user == root ];then
    then
    echo "please switch user root"
    fi

    [root@server ~]# bash choice3.sh # root账户下执行
    [root@server ~]# pwd
    /root
    [root@server ~]# mv choice3.sh / # 让普通账户能访问脚本,需要移动到/
    [root@server ~]# chmod +x /choice3.sh # 赋予执行权限
    [root@server ~]# ll /choice3.sh
    -rwxr-xr-x 1 root root 81 6月 18 10:10 /choice3.sh
    [root@server ~]# tail -1 /etc/passwd # 查看普通账户名
    fox:x:1000:1000::/home/fox:/bin/bash
    [root@server ~]# su fox # 切换账户
    [fox@server root]$ cd /
    [fox@server /]$ bash choice3.sh
    please switch user root

  • 例4:编写脚本choice4.sh,实现闰年的判断

    [root@server ~]# vim choice4.sh
    #!/bin/bash

    read -p "请输入4位数整数年份: " year
    if [ -n "$year" ] # 非空测试
    then
    if ((year%4==0)) && ((year%100!=0)) || ((year%400==0))
    then
    echo "闰年"
    else
    echo "平年"
    fi
    else
    echo "请输入有效4位整数年份"
    fi

  • 例5:判断数字大于500则执行big.sh 小于等于500则退出脚本,并输出报错信息

    read -p "s数字" num
    if [ $num -gt 500 ] ;then
    bash /big.sh
    else
    exit 0
    fi

  • 例6:编写脚本choice5.sh,判断sshd是否运行

    分析:核心在于判断进程是否运行的方法?
    方法1:查看进程 systemctl is-active sshd systemctl status sshd
    [root@localhost ~]# ps -elf | grep sshd | grep -v grep | wc -l
    4
    方法2:查看端口
    本地查看netstat、ss、lsof --- https://www.jianshu.com/p/644e75af4405
    远程查看telnet、nmap、nc
    [root@localhost ~]# netstat -lnupt | grep 22 | wc -l
    2
    [root@localhost ~]# ss -lnupt | grep 22 | wc -l
    2
    [root@localhost ~]# lsof -i:22
    [root@localhost ~]# nmap -p 22 127.0.0.1 | grep open | wc -l
    1

    分析

    根据进程数判断

    [root@server ~]# ps -ef | grep sshd | grep -v grep | wc -l

    根据端口号判断

    [root@server ~]# netstat -lntup | grep 22 | wc -l

    [root@server ~]# vim choice5.sh
    #!/bin/bash

    num=(ps -ef | grep sshd | grep -v grep | wc -l) ​ if ((num>0))
    then
    echo "sshd is running"
    else
    echo "sshd is not running"
    fi

    方法2:
    read -p "请输入要判断的程序名称:" server_name
    count=ps -aux | grep -cw $server_name

    if [ $count -gt 1 ];then
    echo $server_name服务已运行
    else
    echo $server_name服务未运行
    fi

  • 例7:面试题,编写脚本choice6.sh,判断主机是否存活

    [root@server ~]# vim choice6.sh
    #!/bin/bash

    read -p "请输入测试主机的IP地址:" ip

    ping -c 2 -w 3 $ip &> /dev/null

    -c 2 表示发送2个数据包,-w 3 表示等待3秒结束,注意:不能等待1秒结束,有可能第二个数据包没有ping完就结束了,会返回错误的状态码


    if [ ? -eq 0 ] then echo "主机ip 已运行"
    else
    echo "主机$ip 未运行"
    fi

    上例修改,使用循环测试多台主机是否存活,设置显示颜色

    [root@server ~]# vim choice6.sh
    #!/bin/bash

    for ip in 192.168.48.{125..135}
    do

    ping -c 2 -w 3 $ip &> /dev/null
    if [ $? -eq 0 ]
    then
    echo -e "\e[1;31m!!主机 ip 已运行!!\e[0m" # 高亮、红色 else echo "主机ip 未运行"
    fi
    done

  • 例8:编写脚本choice7.sh,输入百分制成绩,判断等级成绩

    [root@server ~]# vim choice7.sh
    #!/bin/bash

    read -p "请输入百分制成绩: " score

    if [ -z $score ]
    then
    echo "未输入,请重新输入"
    elif [ $score -lt 0 -o $score -gt 100 ]
    then
    echo "成绩输入有误,请输入0-100间数字"
    elif [ $score -ge 90 ]
    then
    echo "成绩优秀"
    elif [ $score -ge 80 ]
    then
    echo "成绩良好"
    elif [ $score -ge 60 ]
    then
    echo "成绩及格"
    else
    echo "补考"
    fi

  • 扩展:根据用户输入成绩,判断优良中差。85-100 优秀--A 70-84 良好--B 60-69 合格--C 60分以下不合格--D

    read -p "Please enter your score (0-100): " grade

    if [ grade -ge 85 ] then echo "grade, A"
    elif [ grade -ge 70 ] then echo "grade, B"
    elif [ grade -ge 60 ] then echo "grade, C"
    else
    echo "$grade, D"
    fi

    更完善的:(多层嵌套)
    grade=$1

    if [[ 1 =~ ^[0-9]* ]];then #判断是否是纯数值,有小数也不行
    if [ $grade -ge 85 -a grade -le 100 ];then echo "grade, A"
    elif [ $grade -ge 70 -a grade -le 84 ];then echo "grade, B"
    elif [ $grade -ge 60 -a grade -le 69 ];then echo "grade, C"
    elif [ $grade -ge 0 -a grade -le 60 ];then echo "grade, D"
    else
    echo "输入的成绩不在(0-100)范围内"
    fi
    else
    echo "请输入正确成绩"
    fi

    解释:1 =~ ^[0-9]*
    =~:正则符匹配
    ^[0-9]:以0-9开头的任意一个
    *:匹配前一个字符任意次(正则符)
    $:结束符(保证数值结束前后没有其他信息)

  • 例9:编写脚本,根据用户输入的内容,判断是数字、字母、其它字符

    [root@server ~]# vim choice8.sh

    #!/bin/bash

    read -p "请输入数字、字母、符号: " str

    if echo $str | grep [a-zA-Z] > /dev/null
    then
    echo "字母"
    elif echo $str | grep [0-9] > /dev/null
    then
    echo "数字"
    else
    echo "符号"
    fi

  • 例10:编写脚本choice9.sh,判断当前主机cpu生产商

其信息在/proc/cpuinfo文件中vendor_id一行中。 如果其生产商为GenuineIntel,就显示其为Intel公司; 如果其生产商为AuthenticAMD,就显示其为AMD公司; 否则,就显示无法识别;

[root@server ~]# vim  choice9.sh
#!/bin/bash
​
vendor=$(grep  "vendor_id"  /proc/cpuinfo | uniq | cut -d " " -f2)
​
if [ $vendor == GenuineIntel ]
then    
        echo  "Intel"
elif [ $vendor == AuthenticAMD ]
then    
        echo  "AMD"
else    
        echo   "other"
fi   
  • 例11:两个整数比较大小(if嵌套)

    read -p "请输入整数" a
    read -p "在次输入" b
    if [ -n "a" -a -n "b" ];then
    [[ "a" =~ ^[0-9]+ ]] && [[ "b" =~ ^[0-9]+ ]]
    # echo "a"|[ -n "`sed -n '/^[0-9]*/p'" ] && echo "$b" |[-n "sed -n '/^[0-9]*$/p'`"]
    if [ ? -eq 0 ];then if [[ "a" -gt "b" ]];then echo 第一个数大于第二个数 elif [[ "a" -lt "$b" ]];then
    echo 第一个数小于第二个数
    else
    echo 两个数相等
    fi
    else
    echo 请输入数字
    fi
    else
    echo 输入信息不能为空
    fi

exit退出程序 (复习)

  • exit语句的基本作用是终止Shell程序的执行。
  • 除此之外,exit语句还可以带一个可选的参数,用来指定程序退出时的状态码。
  • exit语句的基本语法如下: exit status
  • 其中,status参数表示退出状态,该参数是一个整数值,其取值范围为0~255。
  • 与其他的Shell命令的一样,Shell程序的退出状态也储存在系统变量$?中,因此,用户可以通过该变量取得Shell程序返回给父进程的退出状态码。

case多条件判断

case可针对谋变量不同的值结果进行情景分析。

格式

case 变量名 in
    值1)
     指令1
    ;;
    值2)
     指令2
    ;;
    值3)
     指令3 
    ;;
    *)
    默认 
esac


也可以写在一行,例:  值1) 指令1 ;;  
最后一个;;可以写也可以不写

执行过程

  • case语句会将该变量的值与 )括号中的值相比较,如果与某个值相等,则执行对应语句。

  • 当遇到";;"符号时,就跳出case语句,执行esac语句后面的语句。

  • 如果没有与任何一个值相匹配,则执行*)后面的一组语句

示例

  • 例1:编写脚本choice10.sh,对上例7的百分制成绩判断等级成绩进行改写

    [root@server ~]# vim choice10.sh
    #!/bin/bash

    read -p "请输入百分制成绩: " score

    case $score in
    9[0-9]|100)
    echo "成绩优秀"
    ;;
    8[0-9])
    echo "成绩良好"
    ;;
    6[0-9]|7[0-9])
    echo "成绩及格"
    ;;
    *)
    echo "补考"
    esac

  • 例2:判断今天是星期几,根据星期几来判断今天是工作日还是休息日

    [root@server ~]# vim choice11.sh
    #!/bin/bash
    a=date +%w #将日期转换为星期几,用数字0-6表示
    case $a in
    [1-5])
    echo "今天是工作日,社畜没有休息日哦。";;
    [06])
    echo "哦~今天是休息日呢,请好好休息哦~";;
    esac

  • 例3:由用户从键盘输入一个字符,并判断该字符是否为字母、数字或者其他字符, 并输出相应的提示信息

    read -p "Please enter a character, press enter to continue: " -n 1 str
    if echo "str"|grep "[a-zA-Z]" >/dev/null then echo "Input is letter" elif echo "str"|grep "[0-9]" >/dev/null
    then
    echo "Input is number"
    else
    echo "Input is other"
    fi

    read -p "Please enter a character, press enter to continue: " -n 1 KEY
    case "$KEY" in
    [[:alpha:]])
    echo "Input is letter"
    ;;
    [0-9])
    echo "Input is number"
    ;;
    *)
    echo "Input is other characters"
    esac

  • 例4:将判断分数范围多分支语句用case语句实现

    read -p "Please enter your score (0-100): " grade
    case "grade" in 8[5-9]|9[0-9]|100) #{85..100} [85-100] echo "grade, A"
    ;;
    7[0-9]|8[0-4])
    echo "grade, B" ;; 6[0-9]) echo "grade, C"
    ;;
    *)
    echo "$grade, D"
    esac

练习

  • 开发rsync起停脚本

    [root@server ~]# vim cc_rsync

    #!/bin/bash

    if [ "$#" -ne 1 ]; then
    echo "Usage: $0 {start|stop|restart}"
    exit 1
    fi

    当用户选择是start

    case "1" in "start") /usr/bin/rsync --daemon sleep 1 if [ `netstat -lntup | grep rsync | wc -l` -ge 1 ]; then echo "rsync is started" exit 0 fi ;; "stop") killall rsync &>/dev/null sleep 1 if [ `netstat -lntup | grep rsync | wc -l` -eq 0 ]; then echo "rsync is stopped" exit 0 fi ;; "restart") if [ `netstat -lntup | grep rsync | wc -l` -ge 1 ]; then killall rsync &>/dev/null sleep 1 fi /usr/bin/rsync --daemon sleep 1 start_flag=`netstat -lntup | grep rsync | wc -l` #if [ "stop_flag" -eq 0 -a "start_flag" -ge 1 ]; then #if [ "stop_flag" -eq 0 && "$start_flag" -ge 1 ]; then
    if [ netstat -lntup | grep rsync | wc -l -ge 1 ]; then
    echo "rsync is restarted"
    exit 0
    fi
    ;;
    *)
    echo "Usage: $0 {start|stop|restart}"
    esac

扩展远程端口监听 telnet nmap nc

  • nc:netcat 是一个简单的 Unix 工具,它使用 TCP 或 UDP 协议去读写网络连接间的数据。

  • nmap:("Network Mapper")是一个用于网络探索和安全审计的开源工具,被设计用来快速地扫描大规模网络。

  • telnet:被用来交互地通过 TELNET 协议与另一台主机通信。

1)nc 即 netcat。netcat 是一个简单的 Unix 工具,它使用 TCP 或 UDP 协议去读写网络连接间的数据。

它被设计成为一个可信赖的后端工具,可被直接使用或者简单地被其他程序或脚本调用。

与此同时,它也是一个富含功能的网络调试和探索工具,因为它可以创建你所需的几乎所有类型的连接,并且还拥有几个内置的有趣功能。

netcat 有三类功能模式,它们分别为连接模式、监听模式和隧道模式。

nc(netcat)命令的一般语法:

$ nc [-options] [HostName or IP] [PortNumber]

在下面的例子中,我们将检查远程 Linux 系统中的 22 端口是否开启。

假如端口是开启的,你将获得类似下面的输出。

# nc -zvw3 192.168.1.8 22
Connection to 192.168.1.8 22 port [tcp/ssh] succeeded!

命令详解:

  • nc:即执行的命令主体;

  • z:零 I/O 模式(被用来扫描);

  • v:显式地输出;

  • w3:设置超时时间为 3 秒;

  • 192.168.1.8:目标系统的 IP 地址;

  • 22:需要验证的端口。

当检测到端口没有开启,你将获得如下输出:

# nc -zvw3 192.168.1.95 22
nc: connect to 192.168.1.95 port 22 (tcp) failed: Connection refused

2)nmap("Network Mapper")是一个用于网络探索和安全审计的开源工具,被设计用来快速地扫描大规模网络,尽管对于单个主机它也同样能够正常工作。

nmap 以一种新颖的方式,使用裸 IP 包来决定网络中的主机是否可达,这些主机正提供什么服务(应用名和版本号),它们运行的操作系统(系统的版本),它们正在使用的是什么包过滤软件或者防火墙,以及其他额外的特性。

尽管 nmap 通常被用于安全审计,许多系统和网络管理员发现在一些日常任务(例如罗列网络资产、管理服务升级的计划、监视主机或者服务是否正常运行)中,它也同样十分有用。

nmap 的一般语法:

$ nmap [-options] [HostName or IP] [-p] [PortNumber]

假如端口是开启的,你将获得如下的输出:

# nmap 192.168.1.8 -p 22
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-16 03:37 IST Nmap scan report for 192.168.1.8 Host is up (0.00031s latency).
PORT STATE SERVICE
22/tcp open ssh 
Nmap done: 1 IP address (1 host up) scanned in 13.06 seconds

假如端口没有开启,你将得到类似下面的结果:

# nmap 192.168.1.8 -p 80
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-16 04:30 IST
Nmap scan report for 192.168.1.8
Host is up (0.00036s latency).
​
PORT   STATE  SERVICE
80/tcp closed http
​
Nmap done: 1 IP address (1 host up) scanned in 13.07 seconds

3)telnet 命令被用来交互地通过 TELNET 协议与另一台主机通信。

telnet 命令的一般语法:

$ telnet [HostName or IP] 80

假如探测成功,你将看到类似下面的输出:

$ telnet 192.168.1.9 22
Trying 192.168.1.9...
Connected to 192.168.1.9.
Escape character is '^]'.
SSH-2.0-OpenSSH_5.3
^]
Connection closed by foreign host.

假如探测失败,你将看到类似下面的输出:

$ telnet 192.168.1.9 80
Trying 192.168.1.9...
telnet: Unable to connect to remote host: Connection refused

示例 2:检查主机是否存活,并输出结果

 分析:最简单方式是通过ping命令检测
 ping -c 2 -W 1 192.168.95.16 &> /dev/null
 通过$?判断,也可以直接 if ping -c 2 -W 1 192.168.95.16 &> /dev/null测试

扩展:

[root@bogon day04]# dnf whatprovides nmap #查询命令nmap所能提供的安装包

相关推荐
远游客07134 分钟前
centos stream 8下载安装遇到的坑
linux·服务器·centos
马甲是掉不了一点的<.<4 分钟前
本地电脑使用命令行上传文件至远程服务器
linux·scp·cmd·远程文件上传
jingyu飞鸟5 分钟前
centos-stream9系统安装docker
linux·docker·centos
超爱吃士力架34 分钟前
邀请逻辑
java·linux·后端
南宫生39 分钟前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__1 小时前
Web APIs学习 (操作DOM BOM)
学习
LIKEYYLL2 小时前
GNU Octave:特性、使用案例、工具箱、环境与界面
服务器·gnu
云云3213 小时前
搭建云手机平台的技术要求?
服务器·线性代数·安全·智能手机·矩阵
云云3213 小时前
云手机有哪些用途?云手机选择推荐
服务器·线性代数·安全·智能手机·矩阵
数据的世界013 小时前
.NET开发人员学习书籍推荐
学习·.net