【shell笔记】bash中if [ ] 与if [[ ]] 的区别

在阅读到朱双印的博客之 bash中 [ ] 与 [[ ]] 的区别 ,起初有一些费解,现在我搞清楚了,所以也说说我的认识。

首先,我提前搞清楚了一件事,即 【shell笔记】 $?返回值0表示真,1表示假+解释 :

  1. 在C语言中,都是0为假,1为真;
  2. 而在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选项”,使用这两个选项可以判断字符串是否为空。

参考 Shell test 命令 字符串测试

参数 说明
= 等于则为真
!= 不相等则为真
-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=""

参考 Shell 基本运算符 字符串运算符:

  • [ -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"

了解更多

shell中[ ]与[[ ]]的区别

posted @   极客子羽  阅读(2786)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示