【shell笔记】bash中if [ ] 与if [[ ]] 的区别
在阅读到朱双印的博客之 bash中 [ ] 与 [[ ]] 的区别 ,起初有一些费解,现在我搞清楚了,所以也说说我的认识。
首先,我提前搞清楚了一件事,即 【shell笔记】 $?返回值0表示真,1表示假+解释 :
- 在C语言中,都是0为假,1为真;
- 而在Shell脚本语言中,状态码0表示成功(可以理解为真),其他状态码(包括1)表示错误(可以理解为假);
因此,在后文中,我尽量不提及 $?
的返回值是多少,而直接以真或者假来说明。
因为 if condition,如果条件为真,就会进入if块区域内执行命令。
如果你是对
$?
结果很执着的读者,可以去看朱双印的博客原文。
场景一:判断变量是否为空
假如有变量
变量赋值 | if [ $var ] |
if [[ $var ]] |
---|---|---|
var=abc | 真 | 真 |
var="" | 假 | 假 |
如上表所示,变量值非空时 condition 为真。使用上述方法判断变量值是否为空时,[ ] 与 [[ ]] 没有区别。
我们可以使用”!”进行取反,使得变量值为空时,condition 为真。
变量赋值 | if [ ! $var ] |
if [[ ! $var ]] |
if ! [ $var ] |
if ! [[ $var ]] |
---|---|---|---|---|
var=abc | 假 | 假 | 假 | 假 |
var="" | 真 | 真 | 真 | 真 |
测试源码 sh test.sh abc 或者 sh test.sh "" 或者 sh test.sh
#!/bin/bash
var=$1
if [ ! $var ]
then echo '[ ! $var ] == true'
fi
if [[ ! $var ]]
then echo '[[ ! $var ]] == true'
fi
if ! [ $var ]
then echo '! [ $var ] == true'
fi
if ! [[ $var ]]
then echo '! [[ $var ]] == true'
fi
执行 sh test.sh
时,var=$1
是一个没有被声明赋值的变量,其值为空,我们可以使用上述语法,判断变量 var 的值是否为空,变量值为空,返回真,同理,上述示例中,[ ] 与 [[ ]] 没有区别。
那么在判断变量是否为空时,[ ] 与 [[ ]] 的区别在哪里呢?
错误示例: test -n $var
我们知道,在Linux中,我们可以使用test命令判断一个字符串是否为空,test命令为我们提供了”-z选项”与”-n选项”,使用这两个选项可以判断字符串是否为空。
参数 | 说明 |
---|---|
= | 等于则为真 |
!= | 不相等则为真 |
-z 字符串 | 字符串的长度为零则为真 |
-n 字符串 | 字符串的长度不为零则为真 |
测试脚本如下:
#!/bin/bash
var=$1
if test -z $var
then echo 'Length of $var is zero'
fi
if test -n $var
then echo 'Length of $var is not zero'
fi
实验结果如下:
变量赋值 | if test -z $var |
if test -n $var |
---|---|---|
var=abc | 假 | 真 |
var="" | 真 | 真(不符合预期) |
正如上表所示,我们通过test命令判断了字符串是否为空。
但是,当 var=""
时,if test -n $var
为真,这个结果并不符合我们的期望!
正确示例:test -n "$var"
上例中,变量var
的值为空,按照正常的逻辑来说,使用 test -n $var
命令判断变量 var
的值是否为空时,应该返回假。但是上例中,test -n $b
这条命令的返回值却为真(应该为假),这是明显不正确的,所以,为了防止上述情况的发生,在使用test命令的-n选项判断变量的值是否为空时,需要在变量的外侧加上”双引号”,示例如下:
#!/bin/bash
var=$1
if test -z "$var"
then echo 'Length of $var is zero'
fi
if test -n "$var"
then echo 'Length of $var is not zero'
fi
实验结果如下:
变量赋值 | if test -z "$var" |
if test -n "$var" |
---|---|---|
var=abc | 假 | 真 |
var="" | 真 | 假 |
好了,我们已经明白了使用test命令判断变量是否为空时的一些注意点,那么话说回来,这篇文章的主题是介绍[ ]与[[ ]]的区别的,为什么我们要先介绍test命令呢?其实,在Linux中,”[ ]”与”test命令”是等效的,比如,我们也可以使用”-n”或者”-z”结合”[ ]”去判断变量是否为空:
变量赋值 | if [ -z "$var" ] |
if [ -n "$var" ] |
---|---|---|
var=abc | 假 | 真 |
var="" | 真 | 假 |
[ -z $a ]
和[ -z "$a" ]
都可以用作检测字符串长度是否为0,为0返回 true。[ -n "$a" ]
可以用作检测字符串长度是否不为 0,不为 0 返回 true。但是,[ -n $a ]
却不 可以!!!
正确示例:if [[ -n $var ]]
不过,使用”[[ ]]”时则不用考虑这样的问题:
变量赋值 | if [[ -z $var ]] |
if [[ -n $var ]] |
---|---|---|
var=abc | 假 | 真 |
var="" | 真 | 假 |
test -n "" 和 test -z ""
但是,有一个特殊情况,就是不用变量赋值,直接判断 "" 字符串长度是否为空时:
if test -z ""
then echo 'Length of "" is zero'
fi
if test -n ""
then echo 'Length of "" is not zero'
fi
打印结果为:
Length of "" is zero
场景二:布尔运算符和逻辑运算符
布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& |
逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
¦¦ | 逻辑的 OR | [[ $a -lt 100 ¦¦ $b -gt 100 ]] 返回 true |
摘自 Shell 基本运算符
运算符 | 正确使用 | 语法错误 |
---|---|---|
布尔运算符 | if [ 1 -gt 0 -a 0 -lt 1 ] 返回 true |
if [[ 1 -gt 0 -a 0 -lt 1 ]] 报错 syntax error near `-a' |
布尔运算符 | if [ 1 -gt 0 -o 0 -lt 1 ] 返回 true |
if [[ 1 -gt 0 -o 1 -lt 0 ]] 报错 syntax error near `-o' |
逻辑运算符 | if [[ 1 -gt 0 && 0 -lt 1 ]] 返回 true |
if [ 1 -gt 0 && 0 -lt 1 ] 报错 [: missing `]' |
逻辑运算符 | if [[ 1 -gt 0 ¦¦ 0 -lt 1 ]] 返回 true |
if [[ 1 -gt 0 ¦¦ 0 -lt 1 ]] 报错 [: missing `]' |
由此,就得到两个语法要求:
- 在
[[ ]]
内,不能使用”-a”或者”-o”对多个条件进行连接; - 在
[ ]
内,不能使用 && 或者 ¦¦ 对多个条件进行连接;
接着,我们来一下 && 和 ¦¦ 在 [ ]
或者 [[ ]]
外部的使用情况:
运算符 | 正确使用 | 语法错误 |
---|---|---|
多个布尔运算符 | if [ 1 -gt 0 ]&&[ 0 -lt 1 ] 返回 true |
if [ 1 -gt 0 ] -a [ 0 -lt 1 ] 报错 [: too many arguments |
多个布尔运算符 | if [ 1 -gt 0 ] ¦¦[ 0 -lt 1 ] 返回 true |
if [ 1 -gt 0 ] -o [ 1 -lt 0 ] 报错 [: too many arguments |
多个逻辑运算符 | if [[ 1 -gt 0 ]]&&[[ 0 -lt 1 ]] 返回 true |
if [[ 1 -gt 0 ]] -a [[ 0 -lt 1 ]] 报错 syntax error near `]]-a[[' |
多个逻辑运算符 | if [[ 1 -gt 0 ]] ¦¦[[ 0 -lt 1 ]] 返回 true |
if [[ 1 -gt 0 ]] -o [[ 1 -lt 0 ]] 报错 syntax error near `]]-o[[' |
- ”&&”或者”||” 可以在
[ ]
或者[[ ]]
外连接多个条件; - ”-a”或者”-o”则 不能 在
[ ]
或者[[ ]]
外对多个条件进行连接;
需要额外说明的是:
if [[ 1 -gt 0 ]]&&[ 0 -lt 1 ]
返回 true,用”&&”或者”||”可以连接布尔运算符条件和逻辑运算符条件;if [[ 1 -gt 0 ]] && [ 0 -lt 1 ]&& [ 0 -lt 100 ]
返回 true,用”&&”或者”||”可以连接三个及以上的条件;
场景三:正则表达式
比如使用以下代码判断输入是否满足正则表达式:
tel=$1
PHONE_PATTERN="[0-9]{11}"
if [[ $tel =~ $PHONE_PATTERN ]]
then echo true
fi
执行 shell 脚本:
[root@hostname workdir]# chmod +x tel.sh
[root@hostname workdir]# sh tel.sh 13688888888
true
运算符 | 正确使用 | 语法错误 |
---|---|---|
正则表达式 | if [[ 13688888888 =~ [0-9]{11} ]] 返回 true |
if [ 13688888888 =~ [0-9]{11} ] 报错 [: =~: binary operator expected |
由上表的对比执行结果,我们可以得出结论:
=~
只能应用于[[ ]]
中,不能应用于[ ]
中。
场景四:数字大小比较与字符ASCII码大小比较
参考朱双印的博客 shell中’-gt’与’>’的区别 得到以下结论:
在shell中,”-gt”或者”-lt”只能用于比较两个数字的大小,当我们想要比较两个字符的ASCII值时,则必须使用”>”或者”<“,而且需要注意,当使用”双中括号”进行判断时,”>”或者”<“不用转义即可正常使用,当使用”单中括号”进行判断时,”>”或者”<“需要转义后才能正常使用。
准备的测试脚本 test.sh 如下:
#!/bin/bash
a=$1
b=$2
if [ $a -lt $b ]; then echo "[ $a -lt $b ] == true"; fi
if [[ $a -lt $b ]]; then echo "[[ $a -lt $b ]] == true"; fi
if [ $a \< $b ]; then echo "[ $a \< $b ] == true"; fi
if [[ $a < $b ]]; then echo "[[ $a < $b ]] == true"; fi
if [ $a < $b ]
这个写法是错误的,<
会被当做重定向符处理。所以,修改为if [ $a \< $b ]
或者if [[ $a < $b ]]
比较类型 | 执行脚本 | if [ $a -lt $b ] |
if [[ $a -lt $b ]] |
if [ $a \< $b ] |
if [[ $a < $b ]] |
---|---|---|---|---|---|
比较数字 | sh test.sh 1 2 | 真 | 真 | 真 | 真 |
比较数字 | sh test.sh 2 1 | 假 | 假 | 假 | 假 |
比较ASCII码 | sh test.sh a b | 报错[: a: integer expression expected | 报错[[: a: expression recursion level exceeded (error token is "a" | 真 | 真 |
比较ASCII码 | sh test.sh b a | 报错[: b: integer expression expected | 报错[[: a: expression recursion level exceeded (error token is "a" | 假 | 假 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)