[Shell]-4-结构化判断命令

引言

Bash Shell的if判断不同于其他编程语言,它判断的是表达式执行后的退出状态符,如果这个退出状态符是0,则执行then中的指令,如果不为0,则不执行。

文章目录

0×1.if判断与结构

在Bash Shell中,有下面几种if判断语句标准结构:

					#1.直接在if后面写命令(命令的执行结果会输出到屏幕)
					root@qingsword.com:~# vim aa.sh 
					#!/bin/bash
					if pwd  #如果pwd执行成功命令退出状态码等于0
					then    #则会ls出当前目录下的全部文件内容
					        ls $(pwd)
					fi

					#2.将if与then写在同一行,上面的这个语句结构能够使用"分号"将then写在与if同一行
					#!/bin/bash
					if pwd ; then  #笔者更倾向于这一种写法
					        ls $(pwd)
					fi

					#3.使用方括号(方括号和中间的表达式之间必须要有一个空格,例如[ 表达式 ],否则Shell会报错)
					root@qingsword.com:~# vim ax.sh
					#!/bin/bash
					#在所有的判断比较结构中,笔者更推荐这一种写法
					if [ $USER = "root" ] ; then
						echo "root login"
					fi
					root@qingsword.com:~# bash ax.sh
					root login

					#4.使用test命令,效果同中括号
					root@qingsword.com:~# vim ac.sh 
					#!/bin/bash

					a="xx"
					b="aa"
					if test $a = $b ; then
						echo "a=b"
					else
						echo "a!=b"
					fi
					root@qingsword.com:~# bash ac.sh 
					a!=b

					#5.使用elif实现多个条件判断
					root@qingsword.com:~# vim ad.sh
					#!/bin/bash

					x="www.qingsword.com"
					y="qingsword"

					if [ $x = "qingsword.com" ] ; then
						echo "$x"
					elif [ $y = "qingsword" ] ; then
						echo "$y"
					else
						echo "qingsword.com"
					fi
					#执行结果
					root@qingsword.com:~# bash ad.sh 
					qingsword
					

0×2.使用test与中括号测试

在Shell脚本中,比较推荐的一种if条件判断是使用中括号将需要判断的条件括起来,例如:

					root@qingsword.com:~# vim bb.sh 
					#!/bin/bash

					website="www.qingsword.com"
					testdata=""
					#如果website有数据,括号判定将会返回0,从而执行if中的语句
					if [ website ] ; then
						echo $website
					fi
					#当testdata数值为空时,括号判定将会返回非0值,这时if中的内容不会被执行
					if [ testdata ] ; then
						echo $testdata
					fi

					#执行
					root@qingsword.com:~# bash bb.sh 
					www.qingsword.com
					

同样的判断,可以使用test命令来实现,例如上面的判断可以写成下面的形式,执行的结果是一样的:

					root@qingsword.com:~# vim cc.sh 
					#!/bin/bash

					website="www.qingsword.com"
					testdata=""
					if test website ; then
						echo $website
					fi
					if test testdata ; then
						echo $testdata
					fi

					#执行
					root@qingsword.com:~# bash cc.sh 
					www.qingsword.com
					

0×3.数值比较

Shell提供了一些基本的数值比较参数,如下:

n1 -eq n2 检查 n1 是否与 n2 相等;
n1 -ge n2 检查 n1 是否大于或等于 n2;
n1 -gt n2 检查 n1 是否大于 n2;
n1 -le n2 检查 n1 是否小于或等于 n2;
n1 -lt n2 检查 n1 是否小于 n2;
n1 -ne n2 检查 n1 是否不等于 n2;

实例:

					root@qingsword.com:~# vim dd.sh 
					#!/bin/bash

					int_a=11
					int_b=22
					int_c=22

					#-eq比较
					if [ $int_a -eq $int_b ] ; then
						echo "$int_a=$int_b"
					else
						echo "$int_a!=$int_b"
					fi

					#-ge比较
					if [ $int_b -ge $int_c ] ; then
					        echo "$int_b>=$int_c"
					else
					        echo "$int_b<$int_c"
					fi

					#-le比较
					if [ $int_a -le $int_b ] ; then
					        echo "$int_a<=$int_b"
					else
					        echo "$int_a>$int_b"
					fi

					#-gt比较
					if [ $int_a -gt $int_b ] ; then
					        echo "$int_a>$int_b"
					else
					        echo "$int_a<=$int_b"
					fi

					#-lt比较
					if [ $int_a -lt $int_b ] ; then
					        echo "$int_a<$int_b"
					else
					        echo "$int_a>=$int_b"
					fi

					#-ne比较
					if [ $int_b -ne $int_c ] ; then
					        echo "$int_b<>$int_c"
					else
					        echo "$int_b=$int_c"
					fi

					#执行
					root@qingsword.com:~# bash dd.sh 
					11!=22
					22>=22
					11<=22
					11<=22
					11<22
					22=22
					

0×4.字符串比较

下面是字符串常用比较运算与注释:

str1 = str2 检查 str1 是否和 str2 相同;
str1 != str2 检查 str1 是否和 str2 不同;
str1 < str2 检查 str1 是否比 str2 小;
str1 > str2 检查 str1 是否比 str2 大;
-n str1 检查 str1 的长度是否非0;
-z str1 检查 str1 的长度是否为0;

在比较过程中有下面两点需要注意:

1,大于号和小于号必须使用 \符号转义,否则Shell会把它们当作重定向符号,把字符串值当作文件名;
2,在比较测试中,大写字母被认为是小于小写字母的,但 sort 命令恰好相反,当你将同样的 字符串放进文件中并用 sort 命令排序时,小写字母会先出现,这是由各个命令使用的排序技术 不同造成的;

a.比较字符串是否相等

					root@qingsword.com:~# vim ee.sh 
					#!/bin/bash

					str1="abc"
					str2="Abc"
					#注意,比较符号两边必须空格,否则将得到错误的结果
					if [ $str1 = $str2  ] ; then
						echo "$str1=$str2"
					elif [ $str1 != $str2 ] ; then
						echo "$str1!=$str2"
					fi

					#执行
					root@qingsword.com:~# bash ee.sh 
					abc!=Abc
					

b.字符串大小比较

					#通过这个实例可以证实,小写字母在Bash Shell字符串比较中,是大于大写字母的
					root@qingsword.com:~# vim ff.sh
					#!/bin/bash

					str1="WWW.QINGSWORD.COM"
					str2="www.qingsword.com"

					if [ $str1 \> $str2 ] ; then
						echo "$str1>$str2"
					elif [ $str1 \< $str2 ] ; then
						echo "$str1<$str2"
					fi

					#执行
					root@qingsword.com:~# bash ff.sh 
					WWW.QINGSWORD.COM<www.qingsword.com
					

c.判断字符串是否为空

					root@qingsword.com:~# vim gg.sh 
					#!/bin/bash

					str1="www.qingsword.com"
					str2=""

					if [ -n $str1 ] ; then
						echo "str1 $str1 is not empty"
					fi

					if [ -z $str2 ] ; then
					        echo "str2 $str2 is empty"
					fi
					#str3不存在,Bash对未定义的变量,判断都为空字符
					if [ -n $str3 ] ; then
					        echo "str3 $str3 is empty"
					fi

					#执行
					root@qingsword.com:~# bash gg.sh 
					str1 www.qingsword.com is not empty
					str2  is empty
					str3  is empty
					

0×5.文件比较

Bash Shell中的文件比较运算,是所有比较运算中最强大的,下面是文件比较常用的参数与注释:

-d file 检查 file 是否存在并是一个目录;
-e file 检查 file 是否存在;
-f file 检查 file 是否存在并是一个文件;
-r file 检查 file 是否存在并可读;
-s file 检查 file 是否存在并非空;
-w file 检查 file 是否存在并可写;
-x file 检查 file 是否存在并可执行;
-O file 检查 file 是否存在并属当前用户所有;
-G file 检查 file 是否存在并且默认组与当前用户相同;
file1 -nt file2 检查 file1 是否比 file2 新;
file1 -ot file2 检查 file1 是否比 file2 旧;

a.判断目录是否存在

					#判断用户家目录是否存在testdir这个目录
					root@qingsword.com:~# vim hh.sh 
					#!/bin/bash

					if [ -d /$USER/testdir ] ; then
						echo "/$USER/testdir directory exsit"
					else
						echo "/$USER/testdir is not exsit"
					fi

					#执行,笔者使用root用户登录,并且在root家目录中不存在testdir这个目录
					root@qingsword.com:~# bash hh.sh 
					/root/testdir is not exsit
					#创建testdir,再次执行sh脚本
					root@qingsword.com:~# mkdir testdir
					root@qingsword.com:~# bash hh.sh 
					/root/testdir directory exsit
					

b.判断文件是否存在

					root@qingsword.com:~# vim ii.sh 
					#!/bin/bash

					if [ -f /$USER/ii.sh ] ; then
						echo "/$USER/ii.sh file exsit"
					else
						echo "/$USER/ii.sh file not exsit"
					fi

					#上面已经使用vim在用户家目录创建了ii.sh这个文件,所以判断结果是文件存在
					root@qingsword.com:~# bash ii.sh 
					/root/ii.sh file exsit
					

c.判断目录或文件是否存在

					root@qingsword.com:~# vim jj.sh 
					#!/bin/bash

					if [ -e /$USER/jj.sh ] ; then
						echo "/$USER/jj.sh file exsit"
					fi

					if [ -e /$USER/testdir ] ; then
						echo "/$USER/testdir directory exsit"
					fi

					#执行
					root@qingsword.com:~# bash jj.sh 
					/root/jj.sh file exsit
					/root/testdir directory exsit
					

d.判断文件是否可读

					root@qingsword.com:~# vim pp.sh 
					#!/bin/bash
					#首先判断文件是否存在,再判断文件是否可读
					if [ -f /etc/shadow ] ; then
						echo "/etc/shadow exsit"
						if [ -r /etc/shadow ] ; then
							echo "/etc/shadow read"
						fi
					fi
					
					#执行
					root@qingsword.com:~# bash pp.sh
					/etc/shadow exsit
					/etc/shadow read
					

e.检查文件数据是否为空

					root@qingsword.com:~# vim qq.sh 
					#!/bin/bash

					str_file="/home/testfile"

					if [ -f $str_file ] ; then
						echo "file $str_file exsit."
						if [ -s $str_file ] ; then
							echo "$str_file文件中存在数据"
						else
							echo "$str_file为空文件"
							echo "删除$str_file空文件"
							rm -rf /home/testfile
						fi
					fi

					#首先在/home目录中创建一个空testfile文件
					root@qingsword.com:~# touch /home/testfile
					#执行脚本,判断testfile文件为空,并将删除空文件
					root@qingsword.com:~# bash qq.sh
					file /home/testfile exsit.
					/home/testfile为空文件
					删除/home/testfile空文件
					

f.判断文件是否可写

文件的读写判断,对root用户无效,root用户对所有文件,都具有读写权限,下面用root与qingsword两个用户来演示,qingsword为普通用户:

					#使用root用户在/home目录创建一个文件读写判断脚本
					root@qingsword.com:~# vim /home/rr.sh
					#!/bin/bash

					str_file=/home/testfile

					if [ -f $str_file ] ; then
						echo "$str_file exsit"
						if [ -w $str_file ] && [ -r $str_file ] ; then
							echo "$str_file可读写"
						elif [ -w $str_file ] ; then
							echo "$str_file仅可写"
						elif [ -r $str_file ] ; then
							echo "$str_file仅可读"
						fi
					fi

					#将这个脚本的权限改成777,这样普通用户也能够执行
					root@qingsword.com:~# chmod 777 /home/rr.sh

					#在/home目录创建testfile文件
					root@qingsword.com:~# touch /home/testfile
					#将testfile文件权限全部去掉
					root@qingsword.com:~# chmod u-rwx,g-rwx,o-rwx /home/testfile
					root@qingsword.com:~# ls -al /home/testfile 
					---------- 1 root root 0 11月 21 11:03 /home/testfile

					#使用root权限验证,发现root权限仍对testfile文件具有读写权限
					root@qingsword.com:~# bash /home/rr.sh 
					/home/testfile exsit
					/home/testfile可读写

					#切换到普通用户测试,发现普通用户并没有读写权限
					root@qingsword.com:~# su qingsword
					qingsword@qingsword.com:/home$ bash /home/rr.sh 
					/home/testfile exsit
					qingsword@qingsword.com:/home$ exit

					#给普通用户添加可读取权限,并测试
					root@qingsword.com:~# chmod o+r /home/testfile
					root@qingsword.com:~# su qingsword 
					qingsword@qingsword.com:/home$ bash /home/rr.sh 
					/home/testfile exsit
					/home/testfile仅可读
					qingsword@qingsword.com:/home$ exit
					exit

					#给普通用户添加可写权限,并测试
					root@qingsword.com:~# chmod o+w /home/testfile
					root@qingsword.com:~# su qingsword 
					qingsword@qingsword.com:/home$ bash /home/rr.sh 
					/home/testfile exsit
					/home/testfile可读写
					qingsword@qingsword.com:/home$ exit
					exit

					#删除普通用户的可读权限,并测试
					root@qingsword.com:~# chmod o-r /home/testfile 
					root@qingsword.com:~# su qingsword
					qingsword@qingsword.com:/home$ bash /homerr.sh 
					/home/testfile exsit
					/home/testfile仅可写
					

g.判断当前用户对文件是否有可执行权限

					root@qingsword.com:~# vim ss.sh
					#!/bin/bash

					str_file="/home/testfile"

					if [ -f $str_file ] ; then
						if [ -x $str_file ] ; then 
							echo "$str_file当前用户有可执行权限"
						else
							echo "$str_file当前用户没有可执行权限"
						fi
					fi

					#测试
					root@qingsword.com:~# ls -al /home/testfile 
					---------- 1 root root 0 11月 21 11:03 /home/testfile

					root@qingsword.com:~# bash ss.sh 
					/home/testfile当前用户没有可执行权限

					root@qingsword.com:~# chmod u+x /home/testfile 
					root@qingsword.com:~# bash ss.sh 
					/home/testfile当前用户有可执行权限
					

h.检查文件所有者

					#使用root用户和qingsword普通用户分别判断是否为下面这个文件的所有者
					root@qingsword-v:~# ls -al /etc/passwd
					-rw-r--r-- 1 root root 2736 11月  9 13:33 /etc/passwd

					#在/home目录创建脚本
					root@qingsword-v:~# vim /home/tt.sh
					#!/bin/bash

					str_file="/etc/passwd"

					if [ -O $str_file ] ; then
						echo "你是$str_file文件所有者"
					else
						echo "你不是$str_file文件所有者"
					fi

					#给其他用户可执行权限
					root@qingsword-v:~# chmod o+x /home/tt.sh 

					#root用户执行脚本
					root@qingsword-v:~# bash /home/tt.sh 
					你是/etc/passwd文件所有者

					#普通用户执行脚本
					root@qingsword-v:~# su qingsword
					qingsword@qingsword-v:/root$ bash /home/tt.sh 
					你不是/etc/passwd文件所有者
					

i.检查文件或文件夹所属组

如果用户名称叫qingsword,所属默认组叫qingword,此用户同时属于share组,此时有一个文件所属用户为qingsword,所属组为share,使用-G检查这个属于share组的文件时,判断会失败,-G只会检查文件的默认组,如果它匹配了用户的默认组,则测试成功,请看下面的实例:

					#新建一个share组
					root@qingsword-v:~# groupadd share

					#创建rootfile文件,并将属组改成share
					root@qingsword-v:~# touch rootfile
					root@qingsword-v:~# chgrp share rootfile 

					#将root用户放到share组中(如果不添加-a参数,就是从用户默认组中删除用户,然后再放入新组中)
					root@qingsword-v:~# usermod -a -G share root

					root@qingsword-v:~# ls -al rootfile 
					-rw-r--r-- 1 root share 0 11月 21 13:58 rootfile

					#创建脚本文件
					root@qingsword-v:~# vim uu.sh 
					#!/bin/bash

					str_file="/$USER/rootfile"

					if [ -G $str_file ] ; then
						echo "文件$str_file属于$USER组"
					else
						echo "文件$str_file不属于$USER组"
					fi

					#执行,虽然root也属于share组,但文件并不属于root默认组
					root@qingsword-v:~# bash uu.sh 
					文件/root/rootfile不属于root组
					

j.比较文件时间

-nt 比较会判定一个文件是否比另一个文件新,如果文件较新,那意味着它的文件改动时间更近;
-ot 比较会判定一个文件是否比另一个文件旧。如果文件较旧,意味着它的改动日期更早;

					root@qingsword-v:~# vim vv.sh
					#!/bin/bash 
					#定义当前目录下的两个文件,一个是当前脚本文件本身,另一个是之前创建的aa.sh文件
					#所以从修改时间上看,vv.sh要比aa.sh新
					str1="aa.sh"
					str2="vv.sh"

					echo "-nt比较,$str1与$str2"
					if [ $str1 -nt $str2 ] ; then
						echo "文件$str1比$str2新"
					else
						echo "文件$str1比$str2旧"
					fi
					echo "-ot比较,$str1与$str2"
					if [ $str1 -ot $str2 ] ; then
					        echo "文件$str1比$str2旧"
					else    
					        echo "文件$str1比$str2新"
					fi

					#开始执行前,使用stat查看下两个文件的修改时间
					root@qingsword-v:~# stat vv.sh
					  文件:vv.sh
					最近访问:2018-11-13 11:21:13.900376131 +0800
					最近更改:2018-11-13 11:21:07.664667684 +0800
					最近改动:2018-11-13 11:21:07.664667684 +0800 #主要比较这行
					创建时间:-

					root@qingsword-v:~# stat aa.sh
					  文件:aa.sh
					最近访问:2018-11-09 11:56:21.522414614 +0800
					最近更改:2018-11-09 11:56:20.286594043 +0800
					最近改动:2018-11-09 11:56:20.294592871 +0800
					创建时间:-

					#执行
					root@qingsword-v:~# bash vv.sh 
					-nt比较,aa.sh与vv.sh
					文件vv.sh比aa.sh新
					-ot比较,aa.sh与vv.sh
					文件vv.sh比aa.sh新
					

在目前的Linux系统中没有"文件创建时间"的概念,那么如何判断Linux中一个文件的创建时间呢,有下面三种方法:

1,如果文件创建后就没有修改过,修改时间=创建时间;
2,如果文件创建后,状态就没有改变过,那么状态改变时间=创建时间;
3,如果文件创建后,没有被读取过,那么访问时间=创建时间;

0×6.if复合条件测试

if-then 语句允许你使用布尔逻辑来组合测试,这种测试被称为"复合条件测试",目前有两种布尔运算符可用:

[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]

实例:

					root@qingsword-v:~# vim ww.sh
					#!/bin/bash
					#/home目录存在且在/home目录中存在testfile文件
					if [ -d $HOME ] && [ -f $HOME/testfile ] ; then
						echo "文件$HOME/testfile存在,内容如下"
						cat $HOME/testfile
					else
						echo "文件$HOME/testfile不存在"
					fi

					#判断/home目录下是否存在qingsword或qingsword.com文件
					if [ -e $HOME/qingsword ] || [ -e $HOME/qingsword.com ] ; then
					        echo "目标存在"
					else
					        echo "目标不存在"
					fi

					#第一次测试
					root@qingsword-v:~# bash ww.sh 
					文件/root/testfile不存在
					目标不存在

					#创建qingsword.com文件
					root@qingsword-v:~# touch qingsword.com
					#创建testfile文件,并写入内容
					root@qingsword-v:~# echo www.qingsword.com >> testfile

					#第二次测试
					root@qingsword-v:~# bash ww.sh 
					文件/root/testfile存在,内容如下
					www.qingsword.com
					目标存在
					

0×7.Shell高级特性

a.运算

Shell中支持的运算符如下:

val++ 后增;
val-- 后减;
++val 先增;
--val 先减;
! 逻辑求反;
~ 位求反;
** 幂运算;
<< 左位移;
>> 右位移;
& 位布尔和;
| 位布尔或;
&& 逻辑和;
|| 逻辑或;

Bash Shell支持的运算语句可以放在"$[表达式]"符号中,或"$((表达式))"符号中,或者使用let命令,本文下面使用"$[表达式]"形式来实例演示:

					root@qingsword-v:~# vim calc.sh
					#!/bin/bash

					int_a=11
					int_b=12
					int_c=4

					echo "初始变量值:"
					echo "int_a=$int_a"
					echo "int_b=$int_b"
					echo "int_c=$int_c"

					#可以使用++或--让变量自增或自减,符号在变量后,在执行到这个变量后增语句的时候,会执行完这条语句之后,变量再自增1,例如下面的语句,第二句echo输出后,int_a才加1,这个时候第二句echo输出的int_a的值还是原来的11,但是第三条语句输出的就是int_a增加后的12
					echo "变量int_a后增1"
					echo "int_a=$[int_a++]"
					echo "int_a=$int_a"

					#同理,符号在变量前,当执行这条语句之前,变量加1
					echo "变量int_b先增1"
					echo "int_b=$[++int_b]"
					echo "int_b=$int_b"

					#计算int_c的平方得到的结果是否大于int_b的值,如果大于,将int_c的平方的结果赋予int_c本身,然后打印出来
					if [ $[int_c**2] -gt $int_b ] ; then
						int_c=$[int_c**2]
						echo "int_c=$int_c"
					fi

					#执行
					root@qingsword-v:~# bash calc.sh 
					初始变量值:
					int_a=11
					int_b=12
					int_c=4
					变量int_a后增1
					int_a=11
					int_a=12
					变量int_b先增1
					int_b=13
					int_b=13
					int_c=16
					

b.模式匹配

Shell中的模式匹配表达式非常的多,下面只介绍一种模式匹配方法,在下面的脚本中,我们使用了双等号( == ),双等号将右边的字符串( r* )视为一个模式,并应用模式匹配规则,模式匹配表达式被包含在一对双括号中,当表达式左侧的 $USER 环境变量是以字母r开头,比较通过,shell会执行 then 部分的命令:

					root@qingsword-v:~# vim zz.sh
					#!/bin/bash

					if [[ $USER == r* ]] ; then
						echo "Welcome $USER"
					else
						echo "认证失败"
					fi

					#使用root执行
					root@qingsword-v:~# bash zz.sh 
					Welcome root
					

0×8.使用case命令

在Shell中,case命令与if-then-else类似,在判断语句不是很复杂的情况下,推荐使用case,它的代码量比case要少而简洁。

					#case语法结构
					case 需要比较的参数 in
						匹配值1 | 匹配值2 | ... |  匹配值N)
							匹配后执行的语句;;
						匹配值)
							如果匹配后需要执行多条语句
							匹配后执行的语句
							在最后一行后面,必须添加双分号作为结束;;
						*)
							在上面的匹配值都没有匹配到时,执行这一段
							相当于if中的else;;
					esac

					#这个脚本判断当前登录的用户名,因为登录的为root用户,所以匹配到qingsword | root中的root,然后执行下面的两条echo语句
					root@qingsword-v:~# vim case.sh
					#!/bin/bash

					case $USER in
						qingsword | root)
							echo "qingsword or root"
							echo "Welcome $USER";;
						qings)
							echo "qings";;
						sword)
							echo "sword";;
						*)
							echo "other";;
					esac

					#使用root执行脚本
					root@qingsword-v:~# bash case.sh 
					qingsword or root
					Welcome root