条件判断、流程控制以及循环语句

1、条件判断语法结构

1.1 条件判断语法格式

格式1:test 条件表达式
格式2:[ 条件表达式 ]
格式3:[[ 条件表达式 ]] 支持正则 =~

特别说明:[ ] 和 [[ ]] 两边都有空格

更多判断可以采用man test 去查看,很多参数都用来进行条件判断

有空格和无空格区别:

[条件表达式]  	#无空格
[ 条件表达式 ]	#有空格

[[条件表达式]]  	#无空格
[[ 条件表达式 ]]	#有空格

1.2 条件判断相关参数(常用)

判断文件类型

判断参数含义
-e判断文件是否存在(任何类型文件)
-f判断文件是否存在并且是一个普通文件
-d判断文件是否存在并且是一个目录
-L判断文件是否存在并且是一个软连接文件
-b判断文件是否存在并且是一个块设备文件
-S判断文件是否存在并且是一个套接字文件
-c判断文件是否存在并且是一个字符设备文件
-p判断文件是否存在并且是一个命名管道文件
-s判断文件是否存在并且是一个非空文件(有内容)
[ -d ./test1 ];echo $?	#判断当前目录下是否存在名为test1的目录,如果存在,打印结果为0

[ -L ./test2 ];echo $?	#判断当前目录下是否存在名为test1的软链接,如果存在,打印结果为0

[ ! -f ./test2 ];echo $?	#如果当前目录下不存在名为test2的普通文件,则打印0

判断文件权限

判断参数含义
-r当前用户对其是否可读
-w当前用户对其是否可写
-x当前用户对其是否可执行
-u是否有suid,高级权限冒险位
-g是否sgid,高级权限强制位
-k是否有t位,高级权限粘滞位

判断文件新旧

说明:这里的新旧指的是文件的修改时间

判断参数含义
file1 -nt file2比较file1是否比file2新
file1 -ot file2比较file1是否比file2旧
file1 -ef file2比较是否为同一个文件,或者用于判断硬链接是否指向同一个inode

判断整数

判断参数含义
-eq相等
-ne不等
-gt大于
-lt小于
-ge大于等于
-le小于等于

判断字符串

判断参数含义
-z判断是否为空字符串,字符串长度为0则成立
-n判断是否为非空字符串,字符串长度不为0则成立
string1 = string2判断字符串是否相等
string1 != string2判断字符串是否相不等

多重条件判断

判断符号含义举例
-a 和 &&逻辑与[ 1 -eq 1 -a 1 -ne 0 ] [ 1 -eq 1 ] && [ 1 -ne 0 ]
-o 和 ||逻辑或[ 1 -eq 1 -o -ne 1 ] [ 1 -eq 1 ]

特别说明:
前面的表达式为真,才会执行后面的代码
前面的表达式为假,才会执行后面的代码
只用于分割命令或表达式
&& 和 || 没有优先级,从左往右依次计算

数值比较

[ $(id -u) -eq 0 ] && echo "admin"		#如果当前用户为root,则打印admin

[ $(id -u) -eq 0 ] || echo "user"		#如果当前用户不为root,则打印user

类C风格比较

注意:在(())中,=表示赋值,==表示判断
((1==2));echo $?
((1<2));echo $?
((2>=1));echo $?
((2!=1));echo $?
((`id -u`==0));echo $?
((a=123));echo $a
unset a
((a==123));echo $?

字符串比较

a="hello world";b="world"
[ $a = $b ];echo $?
[ "$a" = "$b" ];echo $?`	#判断字符串相等
[ "$a" != "$b" ];echo $?
[ "$a" !== "$b" ];echo $?	#错误写法
[ "$a" == "$b" ];echo $?	#判断字符串相等
test "$a" != "$b";echo $?

[ ] 和 [[ ]]的区别

区别1:
[root@fl ~]# a=
[root@fl ~]# [ $a = hello ];echo $?
bash: [: =: unary operator expected
2
[root@fl ~]# [ $a = "hello" ];echo $?
bash: [: =: unary operator expected
2
[root@fl ~]# [ "$a" = "hello" ];echo $?
1
[root@fl ~]# [[ $a = hello ]];echo $?
1


区别2:
[root@fl Shell]# [ -e test1.sh && 1 -eq 1 ];echo "正确"
bash: [: missing `]'
正确
[root@fl Shell]# [[ -e test1.sh && 1 -eq 1 ]];echo "正确"
正确

总的来说:[[ ]] 还支持逻辑操作符 && 和 ||,支持正则表达式,支持整数比较符(=、>、<、>=、<=),而[ ] 不支持

2、流程控制语句

2.1 基本语法结构

if结构

if [ condition ];then
		command
fi

if test conditon;then
		command
fi

if [[ condition ]];then
		command
fi

[ 条件 ] && command

if…else结构

if [ condition ];then
		command1
	else
		command2
if

[ 条件 ] && command1 || command2

案例:让用户自己输入字符串,如果输入"hello",则打印"world",否则打印"请输入hello"

#!/bin/env bash 

read -p "请输入一个字符串" str

if [ "$str" = "hello" ];then
    echo "world"
else 
	echo "请输入hello"
fi

if…elif…else结构

if [ condition1 ];then
	command1	#结束		
elif [ condition2 ];then
	command2	#结束
else
	command3	#结束
fi

2.2 应用案例

案例1:判断当前主机是否和远程主机是否ping通

#!/bin/env bash

# 用户输入对端主机
read -p "请输入对端主机IP:" ip

# ping 10次
ping -c 10 ${ip} &>/dev/null 	#/dev/null是一个黑洞文件,往里面写的数据都将被丢弃

# 判断是否互通
if [ $? -eq 0 ];then
    echo "当前主机和远程主机${ip}是互通的"
else
    echo "当前主机和远程主机${ip}不是互通的"
fi

案例2:判断web服务器中的httpd进程是否存在

# 方法1
ps -axj | grep httpd | grep -v "grep" &>/dev/null  # grep -v "grep" 表示除去当前的grep进程

if [ $? -eq 0 ];then
    echo "httpd进程存在"
else
   echo "httpd进程存在"
fi


# 方法2
pgrep httpd &>/dev/null
if [ $? -eq 0 ];then
    echo "httpd进程存在"
else
   echo "httpd进程存在"
fi


# 或者
test $? -eq 0 && echo "httpd进程存在" || echo "httpd进程不存在"

pgrep命令
以名称为依据从运行进程队列中查找进程,并显示查找到的进程id
选项:

-o:	仅显示找到的最小(起始)进程号;
-n:	仅显示找到的最大(结束)进程号;
-l:	显示进程名称;
-P: 指定父进程号; pgrep -p 4764 查看父进程下的子进程id
-g: 指定进程组;
-t: 指定开启进程的终端;
-u: 指定进程的有效用户ID

案例3:判断门户网站是否能正常访问

#!/bin/env bash

# wget命令用于从一个网站中下载文件,如果能下载成功,则表示该网站能正常访问
web_server=www.baidu.com
wget -P /dev/null ${web_server} &>/dev/null		#-P 表示下载文件的保存路径

if [ $? -eq 0 ];then
    echo "能正常访问"
else
    echo "不能正常访问"
fi

3、循环语句

列表for循环

for variable in {list}
	do
		command
		command
		...
	done

或者
for variable in a b c
	do
		command
		command
		...
	done
#打印1-10 以下写法结果一样
for i in {1..10}; do echo &i; done

seq 10

for i in $(seq 10); do echo $i; done

for i in 1 2 3 4 5 6 7 8 9 10; do echo $i; done

#打印1 3 5 7 9 以下写法结果一样
for i in{1..10..2}; do echo $i; done

seq 1 2 10

#打印10-1 以下写法结果一样
for i in {1..10..-1}; do echo $i; done

seq 10 -1 1

不带列表循环
不带列表的for循环执行时由用户指定参数和参数的个数

for variable
	do
		command
		command
		...
	done

举例说明

#!/bin/env bash 

for i	#只有一个i,没有范围
do
    echo "hello"
done

[root@fl Shell]# bash test8.sh
[root@fl Shell]# bash test8.sh a
hello
[root@fl Shell]# bash test8.sh a b
hello
hello

# 为什么要带参数才能有执行结果
[root@fl Shell]# bash -x test8.sh a  #会将其解释为以下结果
+ for i in '"$@"'		# "$@"表示脚本后面的所有参数,因此有几个参数就循环几次
+ echo hello
hello

类C风格的for循环

for(( expr1;expr2;expr3 ))
	do
		command
		command
		...
	done
	
for(( i=1;i<=5;i++))
	do
		echo $i
	done

expr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变,决定循环什么时候退出

循环体:do…done之间的内容

  • continue:结束当前循环,进行下次循环
  • break:跳出本次循环
  • exit:直接退出程序
  • shift:使位置参数向左移动,默认移动1位,可以使用shift 2

shift案例:

[root@fl Shell]# cat test15.sh 
#!/bin/env bash
sum=0
while [ $# -ne 0 ]
do
    let sum=$sum+$1
    shift
done
echo sum=$sum
[root@fl Shell]# bash test15.sh 1 2 3 4 5
sum=15

在未运行shift命令之前$1是可用的,当使用shift命令之后,原来的$2会变成$1,并且原有的$1变得不可用,通过$#命令获得的参数个数也会少1

案例4:批量创建用户
批量加5个新用户,以u1到u5命名, 并统一加一个新组,组名为class,统一改密码为123

#!/bin/env bash

#判断class组是否存在
grep -w ^class /etc/group &>/dev/null
#如果不存在就创建class组
if [ $? -ne 0 ];then
	 groupadd class

#循环创建用户
for i in {1..5}
do
    useradd -G class u$i #创建用户
    echo 123 | passwd --stdin u$i &>/dev/null #设置密码
done

案例5:写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

#!/bin/env bash

if [ ! -d `pwd`/tmp ];then
    mkdir `pwd`/tmp
fi

ip=10.1.1

for((i=1;i<=10;++i))
do
    ping -c1 $ip.$i &>/dev/null
    if [ $? -eq 0 ];then
        echo "$ip.$i ping is ok">>./tmp/ip_up.txt
    else
        echo "$ip.$i ping is down">>./tmp/ip_down.txt
    fi
done

echo "局域网内IP检测完毕"

这样存在一个问题,每次需要等待前一个ping完成后,才能进行下一次ping,并且是前台运行,很耗时,因此可以对代码进行改进

#!/bin/env bash

if [ ! -d `pwd`/tmp ];then
    mkdir `pwd`/tmp
fi

ip=10.1.1

for((i=1;i<=10;++i))
do
{
    ping -c1 $ip.$i &>/dev/null
    if [ $? -eq 0 ];then
        echo "$ip.$i ping is ok">>./tmp/ip_up.txt
    else
        echo "$ip.$i ping is down">>./tmp/ip_down.txt
    fi
}&
done
wait
echo "局域网内IP检测完毕"

并发执行:
{程序}& 表示将程序放到后台并发执行,如果需要等待程序执行完毕再进行后续操作,需要加上wait

while循环

条件为真进入循环,条件未假结束循环

while 表达式
	do
		command...
	done

while [ 1 -eq 1] 或者 (( 1 < 2 ))
	do
		command...
	done

案例6:同步系统时间
需求:
写一个脚本,30秒同步一次系统时间,时间同步服务器www.baidu.com
如果同步失败,则进行邮件报警,每次失败都报警
同步成功,也进行邮件通知,但是成功100次才通知一次

#!/bin/env bash

NTP=www.baidu.com
count=0
while true
do
    ntpdate $NTP &>/dev/null
    if [ $? -ne 0 ];then
        echo "system date failed" | mail -s "check system date" root@localhost
    else
        let count++
        if [ $count -eq 100 ];then
        echo "sysyem date success" | mail -s "check system date" root@localhost && count=0
        fi
    fi
    sleep 30
done

# ntpdate $NTP  本机同步ip地址为NTP的服务器时间  也可换成 rdate -s
# mail -s "check system date" root@localhost  向root发送邮件

until循环
条件未假就进入循环,条件为真就结束循环

untile expreesion 
	do
		command...
	done
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值