shell脚本中的各种表达式介绍和使用
#前言:在shell脚本中,有各种的表达式,包括有条件测试表达式,文件表达式,字符串表达式,整数表达式,接下来我们来了解一下他们的使用方法
1.条件测试表达式
#首先来看一下条件测试语法
#条件测试语法 #说明 1.test <测试表达式> test命令和后面<内容>之间至少有一个空格 2.[ <测试表达式> ] 单中括号进行条件测试表达式,[]的边界和内容之间至少要有一个空格 3.[[ <测试表达式> ]] 双括号,[[]]的边界和内容也是要有空格 4.((<测试表达式>)) 双小括号,两端不用空格
#注意点
1、语法1中的test命令和语法2中的[]是等价的。语法3中的[[]]为扩展的test命令,语法4中的(())常用于计算 2、在[[]](双中括号)中可以使用通配符等进行模式匹配,这是其区别其他集中语法格式的地方 3、&&、||、>、<等操作符可以应用于[[]]中,但不能应用于[]中,在[]中一般用-a、-o、-gt(用于整数)、-lt(用于整数)代替上述操作符 4、对于整数的关系运算,也可以使用shell的算术运算符(())
#详解
1.1.test条件测试的语法和使用
#查看帮助:man test
#介绍:test - check file types and compare values(检查文件类型和比较值)
#语法格式: test <测试表达式>
#test的帮助文档
[root@shell ~]# man test > 1.txt
[root@shell ~]# cat 1.txt
TEST(1) User Commands TEST(1) NAME test - check file types and compare values SYNOPSIS test EXPRESSION test [ EXPRESSION ] [ ] [ OPTION DESCRIPTION Exit with the status determined by EXPRESSION. --help display this help and exit --version output version information and exit An omitted EXPRESSION defaults to false. Otherwise, EXPRESSION is true or false and sets exit status. It is one of: ( EXPRESSION ) EXPRESSION is true ! EXPRESSION EXPRESSION is false EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true -n STRING the length of STRING is nonzero STRING equivalent to -n STRING -z STRING the length of STRING is zero STRING1 = STRING2 the strings are equal STRING1 != STRING2 the strings are not equal INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2 INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2 INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2 INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2 INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2 FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2 FILE1 -ot FILE2 FILE1 is older than FILE2 -b FILE FILE exists and is block special -c FILE FILE exists and is character special -d FILE FILE exists and is a directory -e FILE FILE exists -f FILE FILE exists and is a regular file -g FILE FILE exists and is set-group-ID -G FILE FILE exists and is owned by the effective group ID -h FILE FILE exists and is a symbolic link (same as -L) -k FILE FILE exists and has its sticky bit set -L FILE FILE exists and is a symbolic link (same as -h) -O FILE FILE exists and is owned by the effective user ID -p FILE FILE exists and is a named pipe -r FILE FILE exists and read permission is granted -s FILE FILE exists and has a size greater than zero -S FILE FILE exists and is a socket -t FD file descriptor FD is opened on a terminal -u FILE FILE exists and its set-user-ID bit is set -w FILE FILE exists and write permission is granted -x FILE FILE exists and execute (or search) permission is granted Except for -h and -L, all FILE-related tests dereference symbolic links. Beware that parentheses need to be escaped (e.g., by backslashes) for shells. INTEGER may also be -l STRING, which evaluates to the length of STRING. NOTE: [ honors the --help and --version options, but test does not. test treats each of those as it treats any other nonempty STRING. NOTE: your shell may have its own version of test and/or [, which usually super‐ sedes the version described here. Please refer to your shell's documentation for details about the options it supports. GNU coreutils online help: <http://www.gnu.org/software/coreutils/> Report test translation bugs to <http://translationproject.org/team/> AUTHOR Written by Kevin Braunsdorf and Matthew Bradburn. COPYRIGHT Copyright © 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. SEE ALSO The full documentation for test is maintained as a Texinfo manual. If the info and test programs are properly installed at your site, the command info coreutils 'test invocation' should give you access to the complete manual. GNU coreutils 8.22 August 2019 TEST(1)
#使用
#例一:判断如果file文件存在且为一个文件,就输出true,否则输出false
[root@shell ~]# test -f file && echo true || echo false false
#讲解:因为file这个文件不存在,所以输出false,&&是并且的意思,||表示前面一个执行失败才会执行后面
#例二:使用-z选项(如果测试字符串的长度为0,则表达式成立)
[root@shell ~]# test -z "guoke" && echo 1 || echo 0 0 #因为测试的字符串为guoke,不为空值,所以为假输出0 [root@shell ~]# char="guoke" [root@shell ~]# test -z "$char" && echo 1 || echo 0 0 #因为guoke赋值给了char,所以也不是空值,输出0 [root@shell ~]# char="" [root@shell ~]# test -z "$char" && echo 1 || echo 0 1 #char为空值,所以长度为0,表达式成立输出1
1.2.[]中括号条件测试语法和使用
#语法格式:[ <测试表达式> ]
#注意点:中括号内部的两端都要有空格,[]和test用法一样,test的判断选项也可以在[]中用
#输入两端都有空格的技巧:先输入一对中括号,然后退一个格,输入两个空格,再退一个格
#例子:利用[]加-f选项(如果文件存在且为普通文件则表达式就成立)
[root@shell ~]# [ -f /tmp/guoke.txt ] && echo 1 || echo 0 0 #文件不存在所以输出0 [root@shell ~]# touch /tmp/guoke.txt [root@shell ~]# [ -f /tmp/guoke.txt ] && echo 1 || echo 0 1 #文件存在且为一个普通文件,则输出1 [root@shell ~]# [ -f /tmp/guoke.txt ] && echo 1 1
1.3.[[]] 双中括号条件测试语法及使用
#语法格式:[[ <测试表达式> ]]
#注意点:双中括号的两端需要有空格
#例子:判断文件存在且为一个普通文件
[root@shell ~]# [[ -f /tmp/test.txt ]] && echo 1 || echo 0 0 #文件不存在所以条件不成立,输出0 [root@shell ~]# touch /tmp/test.txt [root@shell ~]# [[ -f /tmp/test.txt ]] && echo 1 || echo 0 1 #文件存在且为普通文件,条件成立,输出1 [root@shell ~]# [[ -f /tmp/test.txt ]] && echo 1 1
1.4.特殊条件测试表达式例子
#判断条件测试表达式的条件成立或不成立后,还需要执行多条命令语句的语法,不用if测试表达式的格式
#当条件1成立时,同时执行多条命令
test 条件1 && { } [ 条件1 ] && { 命令1 命令2 } [[ 条件1 ]] && { }
#例子:当条件成立的时候就执行后面的命令
[root@shell ~]# cat test.sh #!/bin/bash [ $1 -eq 3 ] && { echo 1 echo 2 echo 3 } [root@shell ~]# sh test.sh 3 #传参 1 2 3
#上面的判断相当于下面if语句的效果
if [ 条件1 ];then 命令1 命令2 fi
#关于条件测试表达式的总结
#1.test和[]、[[]]的功能有所重合,因此在工作中选择一种适合自己的一种用,其他的可以看懂别人的写的脚本就好了,可以同man test查看更多参数用法
#2.测试表达式test、[]、[[]]、(())区别总结
测试表达式符号 test [] [[]] (()) 边界是否需要空格 需要 需要 需要 不需要 逻辑操作符 !、-a、-o !、-a、-o !、&&、|| !、&&、|| 整数比较操作符 -eq -gt -lt -ge -le(test,[],[[]]) = < > >= <= 字符串比较操作符 =、==、!= (全部支持) 是否支持通配符匹配 不支持 不支持 支持 不支持
2.文件表达式
#常用的文件测试操作符
#常用操作符 #说明 -f 文件,全称file #文件存在且为普通文件则为真,表达式成立 -d 文件,全称directory #文件存在且为目录则为真,表达式成立 -s 文件,全称size #文件存在且大小不为0为真 -e 文件,全称exist #文件存在则为真 -r 文件,全称read #文件存在且为可读则为真,表达式成立 -w 文件,全称write #文件存在且可写为真,表达式成立 -x 文件,全称executable #文件存在且可执行为真 -L 文件,全称link #文件存在且为链接文件为真 f1 -nt f2,英文newer than #文件f1比文件f2新则为真,根据文件修改时间计算 f1 -ot f2,英文older than #文件f1比文件f2旧为真,根据修改时间计算
#提示:这些操作符对于test,[],[[]]几乎是通用的,可以使用man test查看更多的操作符
#例子:
#1.-f,判断文件是否存在且为普通文件
[root@shell ~]# touch test [root@shell ~]# ls -l test -rw-r--r-- 1 root root 0 Mar 18 16:02 test [root@shell ~]# [ -f test ] && echo 1 || echo 0 1 #解析:因为文件存在且为普通文件,所以为真输出1
#2.-d,判断文件是否存在且为目录
[root@shell ~]# mkdir test1 [root@shell ~]# [ -d test1 ] && echo 1 || echo 0 1 #因为文件存在且为目录,所以为真输出1,如果不存在就输出0
#3.测试文件属性:r,w,x
[root@shell ~]# ls -ld test -rw-r--r-- 1 root root 0 Mar 18 16:02 test [root@shell ~]# [ -r test ] && echo 1 || echo 0 1 #文件存在且可读,为真,输出1 [root@shell ~]# [ -w test ] && echo 1 || echo 0 1 #文件存在且可写,为真,输出1 [root@shell ~]# [ -x test ] && echo 1 || echo 0 0 #文件不可执行,不为真,所以输出0 [root@shell ~]# chmod +x test [root@shell ~]# [ -x test ] && echo 1 || echo 0 1 #加了可执行权限就为真成立了
#提示:测试文件的读、写、执行等属性,不光是根据文件属性rwx的标识来判断,还要看当前执行测试的用户是否真的可以按照对应的权限操作该文件
#测试时变量的特殊写法及问题
#用[]测试变量时,如果被测试的变量不加双引号,那么测试结果可能会是不正确的
#例子
[root@shell ~]# echo $test #不存在的变量 [root@shell ~]# [ -f $test ] && echo 1 || echo 0 #不加引号返回的结果时错误的 1 [root@shell ~]# [ -f "$test" ] && echo 1 || echo 0 #添加以后返回的结果是正确的 0
#注意点:做测试判断时,不一定非要按照前面的如果成立了输出什么,不成立输出什么,可以直接做部分判断
[root@shell ~]# [ -x test ] && echo 1 #如果test文件可执行,就输出1,否则不做任何输出 [root@shell ~]# [ -f /etc ] || echo 0 #如果前面执行失败就输出0,否则不做任何输出 0
3.字符串表达式
#字符串表达式作用:比较两个字符串是否相同、测试字符串的长度是否为0、字符串是否为null等
#常用的字符串测试操作符
#常用字符串操作符 #说明 -z "字符串" 如果字符串长度为0则为真, -n "字符串" 如果字符串长度不为0则为真, "字符串1" = "字符串2" 如果字符串1等于字符串2则为真,可以使用==代替= "字符串1" != "字符串2" 如果字符串1不等于字符串2则为真,不能使用!==代替!=
#提示:
#1.上面的字符串测试操作符必须要有""引起来
#2.比较符号两端要有空格
#3.-n 比较字符串长度是否不为0,如果不为0则为真,用法 [ -n "$my" ]
#4.-z 比较字符串长度是否为0,如果为0则为真,用法 [ -z "$my" ]
#例1:-n,-z参数应用
[root@shell ~]# [ -n "abc" ] && echo 1 || echo 0 1 #-n是不为空则为真,字符串长度为abc,所以长度不是为0,为真输出1 [root@shell ~]# test -n "aa" && echo 1 || echo 0 1 [root@shell ~]# test -n "" && echo 1 || echo 0 0 #字符串为空,不为真,数以输出0 [root@shell ~]# var="test" [root@shell ~]# [ -n "$var" ] && echo 1|| echo 0 1 [root@shell ~]# [ -z "$var" ] && echo 1|| echo 0 0 #-z是为空值为真,不为空值为假,所以输出0, [root@shell ~]# [ "aa" = "aa" ] && echo 1 || echo 0 1 #字符串相等,所以长度为0,为真
#例二:进行字符串比较时,如果等号两端没有空格带来的问题
[root@shell ~]# [ "abc"="1" ]&& echo 1 || echo 0 1 #等号两边没有空格,明显是不成立的也输出了1 [root@shell ~]# [ "abc" = "1" ]&& echo 1 || echo 0 0 #正常现象
#总结:字符串比较时若等号两端没有空格,则会导致判断出现逻辑错误,即使语句没有问题,但是结果依然可能不对
#例三:字符串不加引号可能带来的问题
[root@shell ~]# var="" #将变量内容设置为空 [root@shell ~]# [ -n "$var" ] && echo 1 || echo 0 0 #-n是值不为空则为真,因为变量内容为0,为空值,所以不为真,输出0 [root@shell ~]# [ -n $var ] && echo 1 || echo 0 1 #不加双引号导致返回结果错误 [root@shell ~]# [ -z "$var" ]&& echo 1 || echo 0 1 #-z是字符串长度为0,则为真
#查看有关双引号和等号两端空格的生产系统标准
[root@shell ~]# sed -n '30,31p' /etc/init.d/network # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 6
4.整数表达式
#整数二元比较操作符
在test及[]中使用的比较符号 在[[]]和(())中使用的比较符号 说明 -eq == 或 = 相等,全称equal -ne != 不相等,全称not qeual -gt > 大于,全称greater than -ge >= 大于等于,全称为greater equal -lt < 小于,全称less than -le <= 小于等于,全称less equal
#提示:如果选择整数比较的时候,要确保两边是整数,如[ 2 -eq 1 ]
#注意:"<"和">"在[]中括号里面需要转义,对于数字不转义的结果可能不会报错,但是结果可能不对,=和!=在[]不用转义
#例子
[root@shell ~]# [ 2 > 3 ] && echo 1 || echo 0 1 #结果应该返回0,但是不转义返回了1是错误的 [root@shell ~]# [ 2 \> 3 ] && echo 1 || echo 0 0 #进行转义之后输出正确 [root@shell ~]# [ 2 < 1 ] && echo 1 || echo 0 1 [root@shell ~]# [ 2 \< 1 ] && echo 1 || echo 0 0
#整数比较的推荐用法,使用-eq,-lt,-gt
#例子
[root@shell ~]# [ 13 -lt 24 ] && echo 1 1 #13小于24结果为真就输出1
5.逻辑操作符
#常用的逻辑操作符
在test及[]中使用的比较符号 在[[]]和(())中使用的比较符号 说明 -a && and,且,两端都为真,则结果为真 -o || or,或,两端有一个为真,则结果为真 ! ! not,非,两端相反,则结果为真
#提示
1、逻辑操作符前后的表达式是否成立,一般用真假来表示 2、“!”的中文意思是反,即与一个逻辑值相反的逻辑值 3、-a的中文意思是“与”(and或&&),前后两个逻辑值都为“真”,综合返回值才为真,否则为假 4、-o的中文意思是“或”(or或||),前后两个逻辑值只要有一个为真,返回值就为真 5、连接两行[]、test或[[]]的表达式可用&&或||
#提示:中括号里面不能使用&&字符串,否则报错,在[[]]和(())里面就可以用,可参考上面列出的
[root@shell ~]# [ -f "$f1" && -f "$f2" ] && echo 1 || echo 0 -bash: [: missing `]' 0
#例一:
[root@shell ~]# f1=/etc/rc.local [root@shell ~]# f2=/etc/services [root@shell ~]# [ -f "$f1" -a -f "$f2" ] && echo 1 || echo 0 1 #判断如果f2和f2变量的文件存在且为文件的话,就为真,输出1,如果一个不为真,那么久不为真,就输出0 [root@shell ~]# [[ -f "$f1" && -f "$f2" ]] && echo 1 || echo 0 1 #在[[]]双中括号中就可以使用&& [root@shell ~]# [ -f "$f1" ]&&[ -f "$f2" ] && echo 1 || echo 0 1 #或者在两个[]之间使用&&也可以
#例二:
[root@shell ~]# a=1 [root@shell ~]# b=2 [root@shell ~]# [ "$a" -eq 2 -a "$b" -eq 2 ] && echo 1 || echo 0 0 #如果变量a等于2且变量b也等于2,则为真,否则为假,输出0 [root@shell ~]# [ "$a" -eq 1 -a "$b" -eq 2 ] && echo 1 || echo 0 1 [root@shell ~]# [ "$a" -eq 1 -o "$b" -eq 2 ] && echo 1 || echo 0 1 #如果变量a等于或变量b等于2,则为真,输出1,-o是或,有一个条件成立则为真 [root@shell ~]# [ "$a" -eq 2 -o "$b" -eq 3 ] && echo 1 || echo 0 0