设为首页 收藏本站
查看: 930|回复: 0

[经验分享] Linux基础之bash脚本编程初级-逻辑运算与测试

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-8-17 08:56:15 | 显示全部楼层 |阅读模式
引言
前面介绍了bash编程的基础变量与算术表达式,本文介绍在脚本中的进阶知识:测试
在bash中测试大体分两部分:条件测试、组合测试。
而条件测试有分:数值测试、字符串测试、文件测试。
组合测试则有两种表达方式。具体是什么表达方式在文章中会有具体展示。
                                                       本文实验环境为CentOS7.2



Linux中为什么要学习测试(判断)?


当我第一次学习这部分内容时,觉得好难,好不爽。可是这又是想要继续学习Linux必须要掌握的知识点。为什么?我们在生活中面对各种选择时总要问问自己,我是否应该怎样,不这样会发生什么,在生活中就有诸多类似的“测试”,工作中也离不开,而我们学习Linux掌握这门技术是为了更好的工作,Linux的学习自然也离不开“测试”。当然这么说还有些抽象,那么就举个具体的例子:接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”。
如果你没有学过测试那么此时别人让你写这么一个脚本供他使用,你怎么办?



在正式介绍测试前,我们需要先介绍下在测试中必备的数学知识:逻辑运算

逻辑运算:
逻辑运算在希腊时期就已经出现,不过它正式被运用于数字电路及计算机则是20世纪的一个人物:香农。他在其硕士论文中提出将布尔代数应用于电子领域的概念,并给出能够构建任何逻辑和数值关系的逻辑电路的解决方法。有了香农的贡献才有了如今的计算机。

逻辑运算主要包括三种:与或非,之后在这三种基础上又出现了异或(这里不再介绍)。
在Linux中与或非的运算符号为:
    与 : &&     在测试命令中有时也会用-a表示与
    或 : ||     在测试命令中有时也会用-o表示或
    非 : !
    与、或、非运算:
    与运算: 1 && 1 = 1      1 && 0 = 0
    或运算: 1 || 1 = 1      1 || 0 = 1        0 || 1 = 1         0 || 0 = 0
    非运算:  ! 1 = 0        ! 0 = 1
在计算机中由于用1表示真,0表示假,故上面的三种运算也可以看做如下概念:
    与运算: 真 && 真 = 真   真 && 假 = 真
    或运算: 真 || 真 = 真   真 || 假 = 真     假 || 真 = 真      假 || 假 = 假
    非运算:  ! 真 = 假        ! 假 = 真

在测试中常用的逻辑运算中的定律
德摩根定律:

非(P 且 Q)=(非 P)或(非 Q)

非(P 或 Q)=(非 P)且(非 Q)

它在测试中的作用:通常为了化简逻辑表达式。
比如在一个测试表达式中出现了多个-a或-o使用德摩根定律可以减少其个数
! a == b -a ! c == d -a ! d == a 等价于!( a == b -o c == d -o d == a )
当前面-not或!很多时可以使用这种表示方式,这两种是等价的



测试表达式:
测试表达式分三种:
1、test EXPRESSION
2、[ EXPRESSION ]
3、[[ EXPRESSION ]]
上面三种使用各有其适用范围,限于所学有限没有能力对其进行一一归纳,我觉得刚开始学不需要求全责备,先掌握大体知识框架比较好。之后在实际中遇到再慢慢进行总结。脚本写的多,遇到的问题多,这三种的使用场景自然就心领神会了。




条件测试:数值测试、字符串传测试、文件测试


数值测试:判断两个数值的大小及是否相等,有如下
    -gt:是否大于      大于为真,否则为假
    -ge:是否大于等于  大于等于为真,否则为假
    -eq:是否等于      等于为真,否则为假
    -ne:是否不等于    不等于为真,否则为假
    -lt:是否小于      小于为真,否则为假
    -le:是否小于等于  小于等于为真,否则为假

下面是一个小例子显示其简单用法,$?是执行状态返回值,可以查看上一条命令执行结果的真与假,0表示为真,1-255为假。
1
2
3
[iyunv@localhost test]# [ 1 -eq 2 ]
[iyunv@localhost test]# echo $?
1



我们判断1是否等于2,状态返回值为1判断执行结果为假,所以1不等于2.
………………………………………………………………………………………………………………………
字符串测试:判断字符串是否符合或等于给定的字符串
字符串的判断大小是依据ASCII中字符对应的数字大小进行
    ==:是否等于     等于为真,否则为假
    >:是否大于      大于为真,否则为假
    <:是否小于      小于为真,否则为假
    !=:是否不等于  不等于为真,否则为假
    =~:左侧字符串是否能够被右侧的PATTERN(正则表达式)所匹配  若匹配则为真,否则为假
    -z “string” : 测试字符串是否为空,空则为真,否则为假
    -n “string” :测试字符串是否不为空,不空为真,否则为假

下面也举一个简单的例子展示字符串测试用法
1
2
3
4
5
6
7
8
9
10
[iyunv@localhost test]# [ a == b ]
[iyunv@localhost test]# echo $?
1
[iyunv@localhost test]# [ a < b ]   
-bash: b: 没有那个文件或目录
[iyunv@localhost test]# [ "a" < "b" ]
-bash: b: 没有那个文件或目录
[iyunv@localhost test]# [[ "a" < "b" ]]
[iyunv@localhost test]# echo $?
0



这里我先对ab是否相等进行判断,之后查看结果是假,也就是a不是b。之后对其进行大小判断,然后报错,先为ab加""结果报错,之后又加了[]才未报错。这里我们可以看到在字符串测试中使用[[ ]]方式进行会比较靠谱,但也不一定。用[]还是[[ ]]就是在这种测试中摸索出来的。
下面再对字符是否为空举一个例子
1
2
3
4
5
6
7
[iyunv@localhost test]# name1=
[iyunv@localhost test]# [ -z $name1 ]
[iyunv@localhost test]# echo $?
0
[iyunv@localhost test]# [ -n $name1 ]
[iyunv@localhost test]# echo $?
0



怎么会出现这种情况?字符测试为空竟然不灵!别慌,上面我们曾有经验,字符测试如果单中括号失败那就试试双中括号
1
2
3
4
5
6
[iyunv@localhost test]# [[ -z $name1 ]]
[iyunv@localhost test]# echo $?
0
[iyunv@localhost test]# [[ -n $name1 ]]
[iyunv@localhost test]# echo $?
1



结果终于如愿,上面的两个例子告诉我们,当测试结果并不是对时,调整下中括号往往有奇效。
………………………………………………………………………………………………………………………
文件测试:

1、存在性测试
    -a FILE (少用)
    -e FILE 文件存在性测试,存在为真,否则为假
1
2
3
4
5
6
[iyunv@localhost test]# [ -e /etc/fstab ]
[iyunv@localhost test]# echo $?
0
[iyunv@localhost test]# [[ -e /etc/ftab ]]
[iyunv@localhost test]# echo $?
1




2、存在性及类别测试
    -b FILE:是否存在且为块设备文件,存在为真否则为假
    -c FILE:是否存在且为字符设备文件,存在为真,否则为假
    -f FILE:是否存在且为普通文件,存在为真,否则为假
    -d FILE:是否存在且为目录文件,存在为真,否则为假
    -h FILE 或 -L FILE :是否存在且为链接文件,存在为真,否则为假
    -p FILE:是否存在且为命名管道文件,存在为真,否则为假
    -S FILE:是否存在且为套接字文件,存在为真,否则为假
1
2
3
4
5
6
[iyunv@localhost test]# [ -f /test/if1 ]
[iyunv@localhost test]# echo $?
0
[iyunv@localhost test]# [ -f /test/ ]   
[iyunv@localhost test]# echo $?
1




3、文件权限测试
    -r FILE:是否存在且对当前用户可读,存在为真,否则为假
    -w FILE:是否存在且对当前用户可写,存在为真,否则为假
    -x FILE:是否存在且对当前用户可执行,存在为真,否则为假
1
2
3
4
5
[iyunv@localhost test]# echo $USER
root
[iyunv@localhost test]# [ -r /test/ ]
[iyunv@localhost test]# echo $?
0




4、文件特殊权限测试

    -g FILE:是否存在且拥有sgid,存在为真,否则为假
    -u FILE:是否存在且拥有suid,存在为真,否则为假
    -k FILE:是否存在且拥有sticky,存在为真,否则为假
1
2
3
4
5
[iyunv@localhost test]# [ -g /test/if1 ]
[iyunv@localhost test]# echo $?
1
[iyunv@localhost test]# ll /test/if1
-rwxr-xr-x. 1 root root 149 8月  15 10:34 /test/if1




5、文件大小测试
    -s FILE:是否存在且非空,存在为真,否则为假
1
2
3
4
5
6
7
[iyunv@localhost test]# [ -s /test/file1 ]
[iyunv@localhost test]# echo $?
1
[iyunv@localhost test]# echo > file1
[iyunv@localhost test]# [ -s /test/file1 ]
[iyunv@localhost test]# echo $?
0




6、文件时间戳测试
    -N FILE:文件自上一次被读取之后是否被修改过,被修改过为真,否则为假
选取刚刚被修改过得file1测试
1
2
3
[iyunv@localhost test]# [ -N /test/file1 ]
[iyunv@localhost test]# echo $?
0




7、文件从属关系测试
    -O FILE:当前用户是否为文件的属主,是为真,否为假
    -G FILE:当前用户是否属于文件的属组,是为真,否为假
1
2
3
4
5
[iyunv@localhost test]# [ -O /test/if1 ]
[iyunv@localhost test]# echo $?
0
[iyunv@localhost test]# ll /test/if1
-rwxr-xr-x. 1 root root 149 8月  15 10:34 /test/if1




8、双目测试
    FILE1 -ef FILE2 :FILE1与FILE2是否指向同一个文件系统的相同inode的硬链接,是则为真,否为假
    FILE1 -nt FILE2 :FILE1的mtime是否新于FILE2,是为真,否为假
    FILE1 -ot FILE2 :FILE1的mtime是否旧于FILE2,是为真,否为假
1
2
3
[iyunv@localhost test]# [ /test/if1 -nt /test/file1 ]
[iyunv@localhost test]# echo $?
1



因为file1刚刚被修改过,所以它比if1文件的mtine要新,因为使用-nt故测试结果为假



组合测试


第一种方式:

与  COMMAND1 && COMMAND2   第一条命令为假后不再执行第二条命令,为真方执行。
或  COMMAND1 || COMMAND2   第一条命令为真后不再执行第二条命令,为假方执行。
非  ! COMMAND              对命令结果的真假取反

第二种方式:

EXPRESSION -a EXPRESSION  第一条命令为假后不再执行第二条命令,为真方执行。
EXPRESSION -o EXPRESSION  第一条命令为真后不再执行第二条命令,为假方执行。
! EXPRESSION              对命令结果的真假取反

示例:比较1是否比2小若其为真则进而比较字符name是否等于Name

第一种表达方式:
1
[iyunv@localhost test]# [[ 1 -lt 2 ]] && [[ name == Name ]]



第二种表达方式:
1
2
3
4
[iyunv@localhost test]# [[ 1 -lt 2 -a name == Name ]]   
-bash: 条件表达式中有语法错误
-bash: `-a' 附近有语法错误
[iyunv@localhost test]# [ 1 -lt 2 -a name == Name ]



用[]还是[[ ]]有时真的需要一遍遍的测试。




脚本实践


简要介绍下脚本相关内容
shell脚本也属于一种语言,这种语言属于弱类型,不需要声明数据的存储格式,bash中均当做字符处理,它靠解释器运行。
写脚本前需要在所打开文件第一行顶格给出shebang,解释器路径对于bash就是#!/bin/bash。
运行脚本
1、赋予执行权限,并直接运行此程序文件常见格式为:./文件名
2、直接运行解释器,将脚本以命令参数传递给解释器程序:bash <脚本文件>

脚本实例

1、写一个脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[iyunv@localhost test]# cat scrip1
#!/bin/bash
#
[ $# -lt 1 ] && echo "At least provide one path" && exit 1
lines_space=`grep '^$' $1 | wc -l`
[ $# -eq 1 ] && echo "The space lines of the first file are :$lines_space"
[ $# -gt 1 ] && echo "None message" && exit 2

[iyunv@localhost test]# chmod +x scrip1
[iyunv@localhost test]# ./scrip1 /etc/fstab
The space lines of the first file are :1
[iyunv@localhost test]# ./scrip1 /etc/fstab /etc
None message
[iyunv@localhost test]# ./scrip1
At least provide one path



脚本中用到了特殊变量$#,位置变量$1,数值测试,组合测试,变量引用

2、写一个脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,先判断是否合格IP,否,提示IP格式不合法并退出,是,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[iyunv@localhost test]# cat scrip2
#!/bin/bash
#
[ $# -lt 1 ] && echo "please give one IP address" && exit 1
[ $# -gt 1 ] && echo "this script just match one IP address" && exit 2
[ $# -eq 1 ] && [[ $1 =~ (([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])\.){3}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4]) ]] && ping -c 1 $1 | sed -n '2p'|grep -o '^64' >> /dev/null && echo "该IP地址可访问" || echo "该IP地址不可访问"

[iyunv@localhost test]# chmod +x scrip2
[iyunv@localhost test]# ./scrip2
please give one IP address
[iyunv@localhost test]# ./scrip2 192.168.1.1
该IP地址不可访问
[iyunv@localhost test]# ./scrip2 192.168.85.3
该IP地址可访问
[iyunv@localhost test]# ./scrip2 192.168.85.3 192.168.168.1
this script just match one IP address



上面思路,先判断参数个数,也就是是否在脚本后加IP。然后判断IP是否符合规范,之后进行若IP可ping通给出相应提示,这个脚本的大致思路就是这样。


关于脚本的个人感受

写脚本前先要理清楚思路,这个问题要怎么解决,对哪些内容要进行测试,都需要用到哪些测试方法,需要设置哪些变量,用到哪些组合测试...
上述确定后就开始写,写完再进行调试。很多时候就算自己想的都没错,可是脚本写完依旧不能成功执行或达成想要的结果,因为初学总会出现各种意料不到的情况比如[]与[[ ]]的错误使用,比如命令引用忘记加``等等细节。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-259039-1-1.html 上篇帖子: multicast相关 下篇帖子: linux下测试磁盘的读写IO速度 开发 Linux
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表