Bash 条件判断

警告
本文最后更新于 2023-10-22,文中内容可能已过时。

Bash 条件判断

条件判断是流程判断的一部分,在脚本中使用非常频繁。

if 结构

if是最常用的条件判断结构,只有符合给定条件时,才会执行指定的命令。它的语法如下。

1
2
3
4
5
6
7
if commands; then
  commands
[elif commands; then
  commands...]
[else
  commands]
fi

这个命令分成三个部分:ifelifelse。其中,后两个部分是可选的,而且elif部分可以有多个。

if关键字后面是主要的判断条件,elif用来添加在主条件不成立时的其他判断条件,else则是所有条件都不成立时要执行的部分。

ifthen写在同一行时,需要分号分隔。分号是 Bash 的命令分隔符。它们也可以写成两行,这时不需要分号。

一般我们会写到一行

简单实践:

1
2
3
4
5
if test $USER = "foo"; then
  echo "Hello foo."
else
  echo "You are not foo."
fi

上面的例子中,判断条件是环境变量$USER是否等于foo,如果等于就输出Hello foo.,否则输出其他内容。

1
2
3
4
5
6
7
8
9
if true
then
  echo 'hello world'
fi

if false
then
  echo 'it is false' # 本行不会执行
fi

上面的例子中,truefalse是两个特殊命令,前者代表操作成功,后者代表操作失败。if true意味着命令部分总是会执行,if false意味着命令部分永远不会执行。

除了多行的写法,if结构也可以写成单行。

1
2
3
4
5
$ if true;then name=xiashuo; echo $name; fi
xiashuo
$ if false;then echo $$;fi
$ if true;then echo $$;fi
31334

注意,if关键字后面也可以是一条命令,该条命令执行成功(返回值0),就意味着判断条件成立。

1
2
3
$ if echo 'hi'; then echo 'hello world'; fi
hi
hello world

上面命令中,if后面是一条命令echo 'hi'。该命令会执行,如果返回值是0,则执行then的部分。

if后面可以跟任意数量的命令。这时,所有命令都会执行,但是判断真伪只看最后一个命令,即使前面所有命令都失败,只要最后一个命令返回0,就会执行then的部分。

1
2
$ if false; true; then echo 'hello world'; fi
hello world

上面例子中,if后面有两条命令(false;true;),第二条命令(true)决定了then的部分是否会执行。

Bash 中的if判断跟其他编程语言的if判断的最大的区别是,其他编程语言中的if判断是根据表达式的内容来判定 True 或者 False,而是 Bash 中的if判断则是根据命令执行是否成功来判断 True 或者 False,这样的判断逻辑,非常方便我们写脚本。

下一个小节中我们学习的test命令也是一个命令,也有执行成功和不成功的区别

if实际上是通过变量$?来判断命令是否执行成功,关于$?的信息,请看《Bash 脚本》的命令 / 脚本执行结果小节

test 命令

if结构的判断条件,一般使用test命令,有三种形式。

expression是一个表达式。这个表达式为真,test命令执行成功(返回值为0);表达式为伪,test命令执行失败(返回值为1)。

1
2
3
4
5
6
7
8
# 写法一
test expression

# 写法二
[ expression ]

# 写法三
[[ expression ]]

上面三种形式是等价的,第二种和第三种写法,[]与内部的表达式之间必须有空格。同时,第三种形式还支持正则判断,前两种不支持。

实际上,[这个字符是test命令的一种简写形式,可以看作是一个独立的命令,这解释了为什么它后面必须有空格。

简单实践:

其中文件/opt/shell_script/info.txt是存在的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ test -f /opt/
$ echo $?
1
$ test -f /opt/shell_script/info.txt
$ echo $?
0
$ [ -f /opt/ ]
$ echo $?
1
$ [ -f /opt/shell_script/info.txt ]
$ echo $?
0

Bash 中的if判断跟其他编程语言的if判断的最大的区别是,其他编程语言中的if判断是根据表达式的内容来判定 True 或者 False,而是 Bash 中的if判断则是根据命令执行是否成功来判断 True 或者 False,这样的判断逻辑,非常方便我们写脚本。

下一个小节中我们学习的test命令也是一个命令,也有执行成功和不成功的区别

if实际上是通过变量$?来判断命令是否执行成功,关于$?的信息,请看《Bash 脚本》的命令 / 脚本执行结果小节

test命令放到if判断中

1
2
3
4
5
6
7
8
9
$ if test -f /opt/shell_script/info.txt;then echo "file exist";fi
file exist
# [ 后需要有空格,否则会报错
$ if [-f /opt/shell_script/info.txt] ;then echo "file exist";fi
-bash: [-f: command not found
$ if  [ -f /opt/shell_script/info.txt ] ;then echo "file exist";fi
file exist
$ if  [[ -f /opt/shell_script/info.txt ]] ;then echo "file exist";fi
file exist

判断表达式

if关键字后面,跟的是一个命令。这个命令可以是test命令,也可以是其他命令。命令的返回值($?变量)为0表示判断成立,否则表示不成立。因为这些命令主要是为了得到返回值,所以可以视为表达式。

Bash 中的if判断跟其他编程语言的if判断的最大的区别是,其他编程语言中的if判断是根据表达式的内容来判定 True 或者 False,而是 Bash 中的if判断则是根据命令执行是否成功来判断 True 或者 False,这样的判断逻辑,非常方便我们写脚本。

下一个小节中我们学习的test命令也是一个命令,也有执行成功和不成功的区别

if实际上是通过变量$?来判断命令是否执行成功,关于$?的信息,请看《Bash 脚本》的命令 / 脚本执行结果小节

常用的判断表达式有下面这些。

文件判断

以下表达式用来判断文件状态。

  • [ -a file ]:如果 file 存在,则为true
  • [ -b file ]:如果 file 存在并且是一个块(设备)文件,则为true
  • [ -c file ]:如果 file 存在并且是一个字符(设备)文件,则为true
  • [ -d file ]:如果 file 存在并且是一个目录,则为true常用
  • [ -e file ]:如果 file 存在,则为true常用
  • [ -f file ]:如果 file 存在并且是一个普通文件,则为true常用
  • [ -g file ]:如果 file 存在并且设置了组 ID,则为true
  • [ -G file ]:如果 file 存在并且属于有效的组 ID,则为true
  • [ -h file ]:如果 file 存在并且是符号链接,则为true
  • [ -k file ]:如果 file 存在并且设置了它的“sticky bit”,则为true
  • [ -L file ]:如果 file 存在并且是一个符号链接,则为true
  • [ -N file ]:如果 file 存在并且自上次读取后已被修改,则为true
  • [ -O file ]:如果 file 存在并且属于有效的用户 ID,则为true
  • [ -p file ]:如果 file 存在并且是一个命名管道,则为true
  • [ -r file ]:如果 file 存在并且可读(当前用户有可读权限),则为true常用
  • [ -s file ]:如果 file 存在且其长度大于零,则为true,如果文件为空,则为false常用
  • [ -S file ]:如果 file 存在且是一个网络 socket,则为true
  • [ -t fd ]:如果 fd 是一个文件描述符,并且重定向到终端,则为true。这可以用来判断是否重定向了标准输入/输出/错误。
  • [ -u file ]:如果 file 存在并且设置了 setuid 位,则为true
  • [ -w file ]:如果 file 存在并且可写(当前用户拥有可写权限),则为true常用
  • [ -x file ]:如果 file 存在并且可执行(有效用户有执行/搜索权限),则为true常用
  • [ FILE1 -nt FILE2 ]:如果 FILE1 比 FILE2 的更新时间更近,或者 FILE1 存在而 FILE2 不存在,则为true常用
  • [ FILE1 -ot FILE2 ]:如果 FILE1 比 FILE2 的更新时间更旧,或者 FILE2 存在而 FILE1 不存在,则为true常用
  • [ FILE1 -ef FILE2 ]:如果 FILE1 和 FILE2 引用相同的设备和 inode 编号,则为true

上面代码中,file如果是一个变量,则最好放在双引号之中,这样可以防止变量file为空,从而出错。因为file如果为空,这时[ -e file ]就变成[ -e ],这会被判断为真。而file放在双引号之中,[ -e "file" ]就变成[ -e "" ],这会被判断为伪。

简单实践如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env bash

if [ $# -eq 0 ];then
  echo "please input at least one arguments"
  exit 1
fi

if [ -e "$1" ]; then
  if [ -d "$1" ]; then
    echo "$1 is a directory."
  fi
  if [ -f "$1" ]; then
    echo "$1 is a regular file."
  fi
  if [ -s "$1" ]; then
    echo "$1 is not empty"
  fi
  if [ -r "$1" ]; then
    echo "$1 is readable."
  fi
  if [ -w "$1" ]; then
    echo "$1 is writable."
  fi
  if [ -x "$1" ]; then
    echo "$1 is executable/searchable."
  fi
else
  echo "$1 does not exist"
  exit 1
fi

/opt/shell_script/info.txt文件存在且不为空,/opt/shell_script/test.txt存在且为空,没有内容

对脚本赋权之后执行下面的内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ ./file_condition.sh /opt/
/opt/ is a directory.
/opt/ is not empty
/opt/ is readable.
/opt/ is writable.
/opt/ is executable/searchable.
$ ./file_condition.sh /opt/shell_script/info.txt
/opt/shell_script/info.txt is a regular file.
/opt/shell_script/info.txt is not empty
/opt/shell_script/info.txt is readable.
/opt/shell_script/info.txt is writable.
$ ./file_condition.sh /opt/shell_script/test.txt
/opt/shell_script/test.txt is a regular file.
/opt/shell_script/test.txt is readable.
/opt/shell_script/test.txt is writable.

字符串判断

以下表达式用来判断字符串。

  • [ -n string ]:如果字符串string的长度大于零,则判断为真。即使字符串内容为" ",也是长度大于 0。
  • [ string ]:如果string不为空(长度大于 0),则判断为真。否则为false,效果类似于[ -n string ]
  • [ -z string ]:如果字符串string的长度为零,则判断为真。
  • [ string1 = string2 ]:如果string1string2相同,则判断为真。
  • [ string1 == string2 ] 等同于[ string1 = string2 ]
  • [ string1 != string2 ]:如果string1string2不相同,则判断为真。
  • [ string1 '>' string2 ]:如果按照字典顺序string1排列在string2之后,则判断为真。
  • [ string1 '<' string2 ]:如果按照字典顺序string1排列在string2之前,则判断为真。

注意,test命令内部的><,必须用引号引起来(或者是用反斜杠转义)。否则,它们会被 shell 解释为重定向操作符。

此外,字符串判断时,如果string是变量,则要把其放在双引号之中,比如[ -n "string" ],否则,变量替换成字符串以后,如果字符串变量中包含字符串,test命令可能会报错,提示参数过多。而且,如果不放在双引号之中,变量为空时,命令会变成[ -n ],这时会判断为真。如果放在双引号之中,[ -n "" ]就判断为伪。

简单实践如下

对空字符串的验证

1
2
3
4
5
6
7
8
$ if [ -n "" ];then echo yes;fi
$ if [ -n "  " ];then echo yes;fi
yes
$ if [ "" ];then echo yes;fi
$ if [ " " ];then echo yes;fi
yes
$ if [ -z "" ];then echo yes;fi
yes

字符串的比较

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/usr/bin/env bash

if [ -z "$1" ];then
  echo "please input at least one arguments"
  exit 1
fi
if [ "$1" = "yes" ]; then
  echo "input yes"
elif [ "$1" = "no" ]; then
  echo "input no"
else
  echo "input something else"
fi

赋权后执行

1
2
3
4
5
6
7
8
$ ./str_condition.sh
please input at least one arguments
$ ./str_condition.sh yes
input yes
$ ./str_condition.sh no
input no
$ ./str_condition.sh 113
input something else

整数判断

下面的表达式用于判断整数。

  • [ integer1 -eq integer2 ]:如果integer1等于integer2,则为true
  • [ integer1 -ne integer2 ]:如果integer1不等于integer2,则为true
  • [ integer1 -le integer2 ]:如果integer1小于或等于integer2,则为true
  • [ integer1 -lt integer2 ]:如果integer1小于integer2,则为true
  • [ integer1 -ge integer2 ]:如果integer1大于或等于integer2,则为true
  • [ integer1 -gt integer2 ]:如果integer1大于integer2,则为true

简单实践如下:

创建num_condition.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env bash

if [ -z "$1" ];then
  echo "please input at least one arguments">&2
  exit 1
else
    INT=$1
fi

if [ $INT -eq 0 ]; then
  echo "INT is zero."
else
  if [ $INT -lt 0 ]; then
    echo "INT is negative."
  else
    echo "INT is positive."
  fi
  if [ $((INT % 2)) -eq 0 ]; then
    echo "INT is even."
  else
    echo "INT is odd."
  fi
fi

赋权后执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ ./num_condition.sh
please input at least one arguments
$ ./num_condition.sh 12
INT is positive.
INT is even.
$ ./num_condition.sh -1
INT is negative.
INT is odd.
$ ./num_condition.sh 45
INT is positive.
INT is odd.

正则判断

[[ expression ]]这种判断形式,支持正则表达式。

1
[[ string1 =~ regex ]]

上面的语法中,regex是一个正则表示式,=~是正则比较运算符。

注意,正则表达式跟 globe 类型拓展不是一个概念,要注意区分,不要混为一谈,符号虽然一样,但是意义不一样

关于类型拓展,请看《Bash 的模式拓展》

创建脚本regex_condition.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/bin/env bash

if [ $# -eq 0 ];then
  echo "please input at least one arguments"
  exit 1
fi

if [[ "$1" =~ ^-?[0-9]+$  ]];then
 echo $1 is a integer
else
 echo $1 is not a integer
fi

赋值后运算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ ./regex_condition.sh
please input at least one arguments
$ ./regex_condition.sh 1.12
1.12 is not a integer
$ ./regex_condition.sh 1
1 is a integer
$ ./regex_condition.sh -112
-112 is a integer
$ ./regex_condition.sh -112.12
-112.12 is not a integer

上面代码中,先判断变量的字符串形式,是否满足^-?[0-9]+$的正则模式,如果满足就表明它是一个整数。

关于通配符的含义,请看《Linux 中的正则表达式.docx》

test 判断的逻辑运算

通过逻辑运算,可以把多个test判断表达式结合起来,创造更复杂的判断。三种逻辑运算ANDOR,和NOT,都有自己的专用符号。

  • AND运算:符号&&,也可使用参数-a,但是一般不使用-a,因为不直观。此外要注意,&&需要配合[[ ... ]使用

  • OR运算:符号||,也可使用参数-o,但是一般不使用-o,因为不直观。此外要注意,OR需要配合[[ ... ]使用

  • NOT运算:符号!。使用否定操作符!时,可以直接使用,比如[ ! $var -eq 0 ],不过最好用圆括号确定转义的范围,同时test命令内部使用的圆括号,必须使用引号或者转义,否则会被 Bash 解释。

    最终的写法如下,例如:if [ ! \( $INT -eq 0 \) ]; then echo $INT is not 0; fi

简单实践一下:

首先判断 A 是一个整数,然后判断其是否在 18 和 100 之间,这样才算是一个合法的年龄

创建logic_condition.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env bash

if [ $# -eq 0 ];then
  echo "please input at least one arguments"
  exit 1
fi

MIN_VAL=18
MAX_VAL=100

if [[ "$1" =~ ^-?[0-9]+$  ]];then
 echo $1 is a integer
 if [[ "$1" -gt $MIN_VAL && "$1" -lt $MAX_VAL  ]];then
    echo the input number is in the valid range
 else
    echo the input number is not in the valid range
 fi
else
 echo $1 is not a integer
fi

赋权后执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ ./logic_condition.sh
please input at least one arguments
$ ./logic_condition.sh 45
45 is a integer
the input number is in the valid range
$ ./logic_condition.sh 12
12 is a integer
the input number is not in the valid range
$ ./logic_condition.sh 100
100 is a integer
the input number is not in the valid range
$ ./logic_condition.sh 9
9 is a integer
the input number is not in the valid range
$ ./logic_condition.sh 99
99 is a integer
the input number is in the valid range

算术判断

关于算数运算,请看《Bash 的算术运算》的逻辑运算小节,关于算数表达式的更多细节,请看《Bash 的算术运算》

Bash 还提供了((...))作为算术条件,进行算术运算的判断。相对于整数判断小节中的数字比较方式,确实更简单一些。

1
2
3
if ((3 > 2)); then
  echo "true"
fi

上面代码执行后,会打印出true

注意,算术判断不需要使用test命令,而是直接使用((...))结构。这个结构的返回值,决定了判断的真伪。

算数表达式不返回值,表达式地执行的结果根据算术运算的结果而定。只要算术结果不是0,表达式就算执行成功,即$?为 0。如果表达式结果为0,则表示执行失败,$?就不为0,一般都会为1,这一点跟命令的返回值正好相反,需要小心。

简单实践一下:

创建num_condition_arith.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env bash

if [ -z "$1" ];then
  echo "please input at least one arguments">&2
  exit 1
else
    INT=$1
fi


if (( $INT == 0 )); then
  echo "INT is zero."
else
  if (( $INT < 0 )); then
    echo "INT is negative."
  else
    echo "INT is positive."
  fi
  if (( ((INT % 2)) == 0 )); then
    echo "INT is even."
  else
    echo "INT is odd."
  fi
fi

赋权后执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ ./num_condition_arith.sh
please input at least one arguments
$ ./num_condition_arith.sh 12
INT is positive.
INT is even.
$ ./num_condition_arith.sh -12
INT is negative.
INT is even.
$ ./num_condition_arith.sh -13
INT is negative.
INT is odd.
$ ./num_condition_arith.sh 1
INT is positive.
INT is odd.

普通命令的逻辑运算结合

如果if结构使用的不是test命令,而是普通命令,比如上一节的((...))算术运算,或者test命令与普通命令混用,那么可以使用 Bash 的命令控制操作符&&(AND)和||(OR),进行多个命令的逻辑运算。

我们在《Bash 的基本语法》的命令的有条件的组合小节中曾经学习过Command1 && Command2Command1 || Command2这两个命令

1
2
$ command1 && command2
$ command1 || command2

对于&&操作符,先执行command1,只有command1执行成功后,才会执行command2。对于||操作符,先执行command1,只有command1执行失败后,才会执行command2

1
$ [ -d temp ] || mkdir temp

上面的命令会测试目录temp是否存在,如果不存在,就会执行第二个命令,创建这个目录。这种写法非常有助于在脚本中处理错误。

1
[ ! -d temp ] && exit 1

上面的命令中,如果temp子目录不存在,脚本会终止,并且返回值为1

下面就是if&&结合使用的写法。

1
2
3
if [ condition ] && [ condition ]; then
  command
fi

这里特别容易跟test 判断的逻辑运算小节中提到的 [[ condition1 && condition2 ]]混淆

简单实践一下:

/aaa不存在,直接退出 shell

1
2
3
$ cd /aaa || exit 1
-bash: cd: /aaa: No such file or directory
logout
1
2
$ [ -d /aaa ] || echo /aaa folder not exist
/aaa folder not exist
1
2
3
4
5
$ if [ -e /opt/shell_script/ts.sh ] && [ -e /opt/shell_script/info.txt ];then echo yes ;fi
yes
# 等效于
$ if [[ -e /opt/shell_script/ts.sh &&  -e /opt/shell_script/info.txt ]];then echo yes ;fi
yes

case 结构

类似于 Java 中的switch语法

case结构用于多值判断,可以为每个值指定对应的命令,跟包含多个elifif结构等价,但是语义更好。它的语法如下。

1
2
3
4
5
6
7
case expression in
  pattern )
    commands ;;
  pattern )
    commands ;;
  ...
esac

后面的esaccase的反写,跟if命令的最后是fi一样的规律

上面代码中,expression是一个表达式,pattern是表达式的值或者一个模式,可以有多条,用来匹配多个值,每条以两个分号(;)结尾。

case的匹配模式可以使用各种通配符,下面是一些例子。

  • a):匹配a

  • a|b):匹配ab

  • [[:alpha:]]):匹配单个字母。

  • ???):匹配 3 个字符的单词。

  • 支持量词语法

    关于量词语法,请看《Bash 的模式拓展》的量词语法小节,注意,如果是在脚本中使用,则需要在脚本中通过$ shopt -s extglob开启支持,因为脚本会开启一个子 shell,因此需要单独开启。

  • *.txt):匹配.txt结尾。

  • *):匹配任意输入,通过作为case结构的最后一个模式。

支持《Bash 的模式拓展》中的提到的各种拓展

Bash 4.0 之前,case结构只能匹配一个条件,然后就会退出case结构。Bash 4.0 之后,允许匹配多个条件,这时可以用;;&终止每个条件块。这样,在匹配一个条件之后,并不会退出case结构,而是继续判断下一个条件。

简单实践如下:

创建case_condition.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env bash

if [ $# -eq 0 ];then
  echo "please input at least one arguments"
  exit 1
fi

case "$1" in
  1)
   echo 1
   ;;
  2)
   echo 2
   ;;
  3)
   echo 3
   ;;
  4)
   echo 4
   ;;
  *)
   echo other word
   ;;
esac

赋权后执行

1
2
3
4
5
6
7
8
$ ./case_condition.sh
please input at least one arguments
$ ./case_condition.sh 1
1
$ ./case_condition.sh 12
other word
$ ./case_condition.sh 4
4

上面例子中,最后一条匹配语句的模式是*,这个通配符可以匹配其他字符和没有输入字符的情况,类似ifelse部分。

使用高级通配符

创建case_condition_adv.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env bash

if [ $# -eq 0 ];then
  echo "please input at least one arguments"
  exit 1
fi

# 开启量词语法
shopt -s extglob

case $1 in
  yes|no)
   echo input boolean
   ;;
  +([a-zA-Z]) )
   echo input alpha
   ;;
  ???-???-???)
   echo input product code
   ;;
 +([1-9]) )
   echo input number
   ;;
  *.txt)
   echo input txt file
   ;;
  *)
   echo other word
   ;;
esac

shopt -u extglob

赋权并执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ ./case_condition_adv.sh
please input at least one arguments
$ ./case_condition_adv.sh yes
input boolean
$ ./case_condition_adv.sh afafa
input alpha
$ ./case_condition_adv.sh 123-135-854
input product code
$ ./case_condition_adv.sh 12356
input number
$ ./case_condition_adv.sh info.txt
input txt file
$ ./case_condition_adv.sh 445-afda
other word

在匹配一个条件之后,不退出case结构,继续判断下一个条件。

创建case_condition_not_return.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/usr/bin/env bash

read -n 1 -p "Type a character > "
echo
case $REPLY in
  [[:upper:]])    echo "'$REPLY' is upper case." ;;&
  [[:lower:]])    echo "'$REPLY' is lower case." ;;&
  [[:alpha:]])    echo "'$REPLY' is alphabetic." ;;&
  [[:digit:]])    echo "'$REPLY' is a digit." ;;&
  [[:graph:]])    echo "'$REPLY' is a visible character." ;;&
  [[:punct:]])    echo "'$REPLY' is a punctuation symbol." ;;&
  [[:space:]])    echo "'$REPLY' is a whitespace character." ;;&
  [[:xdigit:]])   echo "'$REPLY' is a hexadecimal digit." ;;&
esac

赋权后执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ ./case_condition_not_return.sh
Type a character > 2
'2' is a digit.
'2' is a visible character.
'2' is a hexadecimal digit.
$ ./case_condition_not_return.sh
Type a character > a
'a' is lower case.
'a' is alphabetic.
'a' is a visible character.
'a' is a hexadecimal digit.
0%