RHCE(第二部分)-----第三章:shell条件测试

第三章:shell条件测试

​ 为了能够正确处理Shell程序运行过程中遇到的各种情况,Linux Shell提供了一组测试运算符。通过这些运算符,Shell程序能够判断某种或者几个条件是否成立。条件测试在各种流程控制语句,例如判断语句和循环语句中发挥了重要的作用,所以,了解和掌握这些条件测试是非常重要的。

3.1 条件测试的基本语法

​ 在Shell程序中,用户可以使用测试语句来测试指定的条件表达式的条件的真或者假。当指定的条件为真时,整个条件测试的返回值为0;反之,如果指定的条件为假,则条件测试语句的返回值为非0值。

格式1: test 条件表达式	test   数值比较   -eq       test a -eq b
					   test   字符比较    a = b   test a == b 
                         [ ] 算数比较 -eq  =  ==但> <运算符有问题需要通过\转义符  -a -o !
                         [ ] 字符比较test支持= ==; 不支持-eq  测试符和测试值之间通过空格分割
                         [[ ]] && ||   算数比较不需要转义符    [[ ]] 可以支持正则   =~
格式2: [ 条件表达式 ] 
格式3: [[ 条件表达式 ]]

重点数值比较符通过字符类的测试测试

test [ ] [[ ]] ---支持正则符
数值比较 test 1-eq 2 (-eq -gt -lt -ge -le -ne) -eq -gt -lt -ge -le -ne -a -o ! -eq -gt -lt -ge -le -ne && || ! --测试符都支持
字符比较 test a = b 或者 test a == b -a -o ! = == -a -o ! = == && || ! a =~ ".*" a == a

注意:[]的左右要有空格。

3.2 文件测试运算符

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回0;否则,返回1。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 0;否则,返回1。 [ -f $file ] 返回 true。
-S 是否为socket文件
-p 是否为管道符文件
-L 是否为链接文件
-u 是否有suid的权限
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了冒险位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
普通文件 (Regular File):
    表示:-
    说明:这是最常见的文件类型,用于存储数据,比如文本文件、图片、可执行文件等。
目录文件 (Directory):
    表示:d
    说明:目录文件用于存储文件和子目录的路径信息,类似于Windows中的文件夹。
符号链接文件 (Symbolic Link):
    表示:l
    说明:符号链接文件类似于Windows中的快捷方式,它指向另一个文件或目录。
块设备文件 (Block Device):
    表示:b
    说明:块设备文件通常用于存储设备,如硬盘分区、CD-ROM等。这些设备以块为单位进行读写。
字符设备文件 (Character Device):
    表示:c
    说明:字符设备文件通常用于串行端口和其他按字符处理的I/O设备,如键盘、鼠标等。
命名管道文件 (Named Pipe):
    表示:p
    说明:命名管道文件用于进程间的通信,允许一个进程将数据写入管道,另一个进程从管道中读取数据。
套接字文件 (Socket):
    表示:s
    说明:套接字文件用于网络通信,它允许不同主机之间的进程进行通信。
在Linux中,你可以使用ls -l命令来查看文件和目录的详细信息,包括文件类型。例如:
ls -l
输出示例:
    -rw-r--r-- 1 user group  4096 Oct  4 12:34 example.txt  # 普通文件
    drwxr-xr-x 2 user group  4096 Oct  4 12:34 example_dir  # 目录文件
    lrwxrwxrwx 1 user group    12 Oct  4 12:34 link_to_file -> example.txt  # 符号链接文件
每一行的第一个字符表示文件的类型,后面的信息包括文件的权限、链接数、所有者、所属组、文件大小和修改时间等。

示例:

//普通文件测试
[root@localhost ~]# touch file1.txt
[root@localhost ~]# [ -f file1.txt ] && echo yes || echo no
yes
//目录测试
[root@localhost ~]# [ -d /tmp ] && echo yes || echo no
yes
//测试文件属性
[root@localhost ~]# ll file1.txt 
-rw-r--r-- 1 root root 0 8月  28 12:30 file1.txt
[root@localhost ~]# [ -r file1.txt ] && echo yes || echo no
yes
[root@localhost ~]# [ -x file1.txt ] && echo yes || echo no
no
[ -e ]
[ -s ]
练习题:
对系统中所有日志文件备份

https://www.jianshu.com/p/382c0d06d13c

判断一个文件是文本文件还是目录文件:

bash 复制代码
[root@localhost day03]# vim 2.sh
[root@localhost day03]# bash 2.sh 
请输入一个文件名(绝对路径表示):/day03
/day03是目录文件
[root@localhost day03]# cat 2.sh
#!/bin/bash
# 要求用户输入一个已存在的文件名(绝对路径表示):判断文件是目录文件还是文本文件
read -p "请输入一个文件名(绝对路径表示):" a
([ -f $a ] && echo $a是文本文件) || ([ -d $a ] && echo $a是目录文件)

3.3 字符串运算符

示例:

bash 复制代码
//-n如果字符串长度不为零输出yes,否则输出no
[root@localhost ~]# [ -n "hello" ] && echo yes || echo no
yes
[root@localhost ~]# [ -n "" ] && echo yes || echo no
no
注意://变量为空时通过[[]]进行测试,[]测试有问题
[root@localhost ~]# str=`grep xixi /etc/passwd`  
[root@localhost ~]# [[ -n $str ]] && echo 有 || echo 无
无
[root@localhost ~]# [ -n $str ] && echo 有 || echo 无
有

//-z如果字符串长度为零输出yes,否则输出no
[root@localhost ~]# [ -z "hello" ] && echo yes || echo no
no
[root@localhost ~]# [ -z "" ] && echo yes || echo n
yes
// 字符串相等比较
注意:=的左右有空格,没有空格将会导致逻辑错误。
[root@localhost ~]# [ "HELLO" = "hello" ] && echo yes || echo no
no
[root@localhost ~]# [ "HELO" != "hello" ] && echo yes || echo no
yes

if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi
if [ $a ]     -------$判断z字符串是否为空,不空为真,空为假
then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi

系统服务脚本案例:

bash 复制代码
[root@localhost ~]# sed -n '30,31p' /etc/init.d/network 
Check that networking is up.
[ "${NETWORKING}" = "no" ] && exit 6

3.3 关系运算符

bash 复制代码
# 数值测试:
[root@localhost day03]# [ 1 -eq 2 ] &&  echo yes || echo no
no
[root@localhost day03]# test 1 -eq 2 && echo yes || echo no
no
[root@localhost day03]# [[ 1 = 2 ]] && echo yes || echo no
no
[root@localhost day03]# [[ 1 -eq  2 ]] && echo yes || echo no
no
[root@localhost day03]# ((1>=2)) && echo yes || echo no
no

# 字符串比较
[root@localhost day03]# [[ "a" == "b" ]]
[root@localhost day03]# echo $?
1

示例:

[root@localhost ~]# [ 5 -gt 3 ] && echo yes || echo no
yes
[root@localhost ~]# [ `id -u` -eq 0 ] && echo admin || echo other
admin
[root@localhost ~]# su - student
[student@localhost ~]$ [ `id -u` -eq 0 ] && echo admin || echo other
other

面试:判断输入是否是数字

#(1)grep过滤判断是否是字符串
read -p "请输入:" str
echo $str | egrep  '^[a-zA-Z]+$'
[ $? -eq 0 ] && echo "您输入的是字符串" || echo "输入的不是字符串"
#(2)字符串运算 =~   A=~B 子串A是否包含子串B
[[ "$str" =~ [a-zA-Z]* ]] && echo "2您输入的是字符串" || echo "2输入的不是字符串" 
#(3)利用通配符,判断指定输入字符是否在字符串中包含
[[ $str = *[a-zA-Z]* ]] && echo 包含字符 ||echo 不包含
#(4)利用case语句
case $str in
        *[a-zA-Z]*)
        echo 是字符串
        ;;
        * )
        echo 不是字符串类型
        ;;
esac
#(5)通过算术运算
expr $str "+" &>/dev/null
[ $? -eq 0 ] && echo 输入的是数字 || echo 输入的是字符
(6)a=1234;echo "$a"|[ -n "`sed -n '/^[0-9][0-9]*$/p'`" ] && echo string a is numbers
if [ -n "$(echo $1| sed -n "/^[0-9]\+$/p")" ];then 
    echo "$1 is number." 
else 
    echo 'no.' 
fi 

[root@localhost ~]# num10=123
[root@localhost ~]# num20=ssss1114ss
[root@localhost ~]# [[ "$num10" =~ ^[0-9]+$ ]];echo $?
0
[root@localhost ~]# [[ "$num20" =~ ^[0-9]+$ ]];echo $?
1
#判断输入的字符是否为整数
## 方法1
		a=1234;echo "$a"|[ -n "`sed -n '/^[0-9]*$/p'`" ] && echo string a is numbers
		  第一个-n是shell的测试标志,对后面的串"`sed -n '/^[0-9][0-9]*$/p'`" 进行测试,如果非空,则结果为真。
		   sed默认会显示所有输入行信息的,sed 的"-n"选项是让sed不要显示,而只显示我们所需要的内容:即后面的表达式所匹配的行,这是通过表达式中加入"p"命令来实现的。
		  /^[0-9][0-9]*$/他的含义是匹配至少由一位数字构成的行
			
## 方法2, 可以,不过不是bash实现的,是使用了grep的正则 -->grep的正则表达式,<<< 就是将后面的内容作为前面命令的标准输入
		#if grep '^[[:digit:]]*$' <<< "$1";then 
		#  echo "$1 is number." 
		#else 
		#  echo 'no.' 
		#fi 	
## 方法3 
		#if [ "$1" -gt 0 ] 2>/dev/null ;then 
		#  echo "$1 is number." 
		#else 
		#  echo 'no.' 
		#fi 
## 方法4,case 
		#case "$1" in 
		#  [1-9][0-9]*)  
		#    echo "$1 is number." 
		#    ;; 
		#  *)  
		#    ;; 
		#esac 
## 方法5,awk 
		#echo $1| awk '{print($0~/^[-]?([0-9])+[.]?([0-9])+$/)?"number":"string"}' 
		
## 方法6,expr 
		expr $1 "+" 10 &> /dev/null
		if [ $? -eq 0 ];then
		  echo "$1 is number"
		else
		  echo "$1 not number"
		fi  

3.4 逻辑操作符/布尔运算符

运算符 说明 布尔符 举例
&& 逻辑的 AND -a [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 逻辑的 OR -o [[ $a -lt 100 || $b -gt 100 ]] 返回 true
非 ! not,非,两端相反,则结果为真

示例:

[root@localhost ~]# [ -f /etc/hosts -a -f /etc/services ] && echo yes || echo no
yes
[root@localhost ~]# [[ -f /etc/hosts && -f /etc/services ]] && echo yes || echo no
yes

总结: 1)算数运算符

​ 2)文件测试

​ 3)字符串运算符 -n

​ 4)关系型运算符

​ 5)逻辑运算符

3.5 命令执行顺序;

复合指令:即一串命令。

()和{}都是对一串的命令进行执行,但有所区别:

相同点: ()和{}都是把一串的命令放在括号里面,如果命令在一行命令之间用;号隔开

()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令

不同点 :

()只是对一串命令重新开一个子shell进行执行, {}对一串命令在当前shell执行

()最后一个命令可以不用分号,{}最后一个命令要用分号

()里的第一个命令和左边括号不必有空格,{}的第一个命令和左括号之间必须要有一个空格

[root@localhost day03]# (cd;pwd;hostname)
/root
localhost.localdomain
[root@localhost day03]# { cd;pwd;hostname; }
/root
localhost.localdomain
[root@localhost ~]# 

示例1:

[root@localhost scripts]# (pwd;cd /tmp;pwd)
/scripts
/tmp
# ()子shell中执行,执行完毕,当前路径不变
[root@localhost tmp]# { pwd;cd /tmp;pwd; } > aaa
/tmp
/tmp
[root@localhost tmp]# pwd;cd /;pwd

示例2:

// 如果目录/abc存在给出提示信息目录已存在,否则创建目录
                          [ -e /abc -a -d /abc ]
方法1:[root@localhost ~]# [ -d /abc ] && echo exists || mkdir /abc
方法2:[root@localhost ~]# [ ! -d /abc ] && mkdir /abc || echo exists

3.6案例分析

示例1:判断当前已登录的用户数,当超过五个时输出"Too many"。
分析:1)如何查看当前登录用户--> who
	      2)已登录的用户数--> who | wc -l
	num=$(who  | wc -l)
	[ $num -gt 5 ] && echo "Too many"

示例2:如果在/home/pushmail目录下不存在leadtone目录,则创建该目录

	path=/home/pushmail/leadtone
	[ -d $path ] || mkdir -p $path
	或 [ ! -d $path ] && mkdir -p $path
	
示例3:判断数字大于500则执行big.sh 小于等于500则退出脚本,并输出报错信息exit 
	read -p "please input num: " n
	[ $n -gt 500 ] && echo "big.sh" || (echo "小于等于500";exit 3)  ----()用于复合指令

示例4:判断当前系统的语言环境,若不是"en_US"时输出提示信息"Not en_US"。
	分析:1)如何获取当前系统语言环境--> LANG
			lang=$LANG
			# echo $lang
			zh_CN.utf8
			文件:/etc/locale.conf
		2)处理字符串
	  方法1:echo $lang | cut -d. -f1
	  方法2:echo $lang | awk -F. '{print $1}'
	  方法3: lang=${LANG%.*} echo $lang
	  lang=$(echo $LANG | cut -d. -f1)
	  [ "$lang" = "en_US" ] || echo "Not en.US"
	  或[ "$lang" != "en_US" ] && echo "Not en.US"
	  # echo $lang
	  zh_CN.utf8	
示例5:用Shell编程,判断一文件是不是目录文件,如果是将其拷贝到 /dev 目录下
	分析:-c 判断是否是字符设备文件
cp -i
	[ $# -ne 1 ] && (echo "no input file...";exit 4)
	[ -c "$1" ] && \cp $1 /dev
示例6:通过ping百度来测试是否能上网
分析:通过命令的返回值来判断ping -i 5 localhost 每隔五秒显示
	ping -c 2  www.baidu.com &>/dev/null   &&  echo  up || echo down
	[ $? -eq 0 ] && echo "net is up..."

面试题:写一个shell脚本来看看你使用最多的命令是哪些,列出你最常用的命令top10。

分析:命令保存文件 /root/.bash_history
# sort /root/.bash_history | uniq -c | sort -nr | head
[root@localhost 桌面]# history | tr -s  " "| cut -d " " -f 3- | sort  | uniq -c | sort -rn  | head

dirname和basename:

[root@localhost day03]# file=/test/1.txt
[root@localhost day03]# dirname $file
/test
[root@localhost day03]# basename $file
1.txt

练习:

bash 复制代码
1、取出/etc/passwd文件的第6行;
2、取出当前系统上所有用户的shell,要求,每种shell只显示一次;
    使用cut、sort结合管道实现
   
3、如果/var/log/messages文件的行数大于100,就显示好大的文件
4、显示/etc目录下所有以pa开头的文件,并统计其个数;ls  /etc | grep ^pa* | wc -l
5、如果用户hadoop不存在就添加,否则显示用户已存在
6、编写一个 Shell 程序 mkf,此程序的功能是:显示 root 下的文件信息,然后建立一个 kk 的文件夹,在此文件夹下建立一个文件 aa,修改此文件的权限为可执行

7、编写一个 Shell 程序 test3,程序执行时从键盘读入一个目录名,然后 显示这个目录下所有文件的信息
8、编写一个 Shell 程序 test4,从键盘读入 x、y 的值,然后做加法运算,最后输出结果

写一个脚本,完成以下要求:
给定一个用户:
	1、如果其UID为0,就显示此为管理员;
	2、否则,就显示其为普通用户;
	
# 练习:写一个脚本
# 判断当前系统上是否有用户的默认shell为bash;
# 如果有,就显示有多少个这类用户;否则,就显示没有这类用户;
[root@localhost day03]# vim lianxi.sh
    bash=$(grep -c '/bin/bash$' /etc/passwd)
    [ $bash -gt 0 ] && echo "有 $bash 个用户的默认shell为bash" || echo "没有用户的默认shell为bash"
[root@localhost day03]# bash lianxi.sh 
有 4 个用户的默认shell为bash

# 练习:写一个脚本
# 给定一个文件,比如/etc/inittab;
# 判断这个文件中是否有空白行;
# 如果有,则显示其空白行数;否则,显示没有空白行。
[root@localhost day03]# vim lianxi2.sh 
    file="/etc/inittab"
    [[ $kong -gt 0 ]] && echo "文件 $file 中有 $kong 个空白行" || echo "文件 $file 中没有空白行"
[root@localhost day03]# bash lianxi2.sh 
文件 /etc/inittab 中没有空白行

# 练习:写一个脚本
# 给定一个用户,判断其UID与GID是否一样;
# 如果一样,就显示此用户为"good guy";否则,就显示此用户为"bad guy"
[root@localhost day03]# vim lianxi3.sh
    read -p "请输入一个用户名:" a
    uid=$(id -u "$a")
    gid=$(id -g "$a")
    [ $? != 0 ] && echo "用户 $a不存在" && exit a
    [ "$uid" == "$gid" ] && echo "用户 $a 是 good guy" || echo "用户 $a 是 bad guy"
[root@localhost day03]# bash lianxi3.sh 
请输入一个用户名:zhou
用户 zhou 是 good guy
相关推荐
worthsen19 分钟前
Linux 服务管理 service systemd systemctl
linux·运维
Xiezequan1 小时前
C语言实现跨主机通讯
linux
巴拉特好队友1 小时前
找到一个linux静态库动态库的好资料.3
linux·运维·服务器
Hacker_Fuchen2 小时前
linux 中 Vi 和 Vim 的使用
linux·运维·vim
努力的小T2 小时前
Debian操作系统相对于Ubuntu有什么优势吗?
linux·运维·服务器·ubuntu·centos·云计算·debian
毒丐2 小时前
Debian系软件管理工具命令大全
linux·运维·debian
陈序缘3 小时前
Ubuntu下PyTorch开发环境配置
linux·pytorch·ubuntu·职场和发展
姜豆豆耶3 小时前
kettle经验篇:Pentaho Repository 类型资源库卡顿问题
linux·运维·华为云·etl
LaoZhangGong1233 小时前
Linux第99步_Linux之点亮LCD
linux·stm32mp157·modetest
恩爸编程5 小时前
Linux 防火墙:守护系统安全的坚固防线
linux·运维·系统安全·linux防火墙·linux防火墙是什么·linux关闭防火墙·linux查看防火墙状态