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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1、条件判断语法结构

1.1 条件判断语法格式

格式1test 条件表达式
格式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
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“条件判断、流程控制以及循环语句” 的相关文章