Shell(七):退出、测试、判断及操作符
1、退出状态
在Linux系统中,每当命令执行完成后,系统都会返回一个退出状态。该退出状态用一整数值表示,用于判断命令运行正确与否。若退出状态值为0,表示命令运行成功;而退出状态值不为0时,则表示命令运行失败。最后一次执行命令的退出状态值保存在内置变量 "$?" 中。
POSIX规定了几种退出状态和退出状态的含义:
状态值 |
含义 |
0 |
表示运行成功,程序执行未遇到任何问题 |
1~125 |
表示运行失败,脚本命令、系统命令错误或参数传递错误 |
126 |
找到了该命令但无法执行 |
127 |
未找到要运行的命令 |
>128 |
命令被系统强行结束 |
通过echo命令显示命令执行后的退出状态,测试文件是否创建成功。
退出状态非0的情况:
2、测试
Linux的Shell命令中存在一组测试命令,该组命令用于测试某种条件或某几种添加是否真实存在。测试命令是判断语句和U型你换语句中条件测试的工具。
2.1、测试结构
测试命令可用于测试表达式的条件的真假。若测试的条件为真,则返回一个0值;若测试的条件为假,将返回一个非0整数值。这一点与C语言相反,在C语言中,条件为真返回一个非0正整数值,条件为假是返回一个0值。
测试命令有两种方式:
test命令进行测试,命令格式为:
test expression
使用 [] 进行测试,命令格式为:
[ expression ]
"[" 是启动测试的命令,要求在 expression 后要有一个 "]" 与其配对。使用该命令是需注意 "[" 和 "]"前的空格不能少。
2.2、整数比较运算符
整数比较运算符用于两个值的比较,测试起比较结果是否符合给定的条件,语法格式为:
test "num1" numeric_operator "num2"
或
[ "num1" numeric_operator "num2" ]
numeric_operator为整数比较运算符,用于比较数值的大小,但这些整数比较运算符不可用于字符串、文件操作。
整数比较运算符 |
描述 |
num1 -eq num2 |
若 num1 等于 num2,测试结果为0 |
num1 -ge num2 |
若 num1 大于或等于 num2,测试结果为0 |
num1 -gt num2 |
若 num1 大于 num2,测试结果为0 |
num1 -le num2 |
若 num1 小于或等于 num2,测试结果为0 |
num1 -lt num2 |
若 num1 小于 num2,测试结果为0 |
num1 -ne num2 |
若 num1 不等于 num2,测试结果为0 |
测试案例如下:
可以对整数变量进行测试,结果如下:
2.3、字符串运算符
字符串运算符可用来测试字符串是否为空,两个字符串是否相等或者不相等。字符串运算符经常用于测试用户输入是否为空或比较字符串变量。
一共有5中字符串运算符,详情如下:
字符串运算符 |
描述 |
string |
测试字符串 string 是否不为空 |
-n string |
测试字符串 string 是否不为空 |
-z string |
测试字符串 string 是否为空 |
string1 = string2 |
测试字符串 string1 是否与 字符串 string2 相同 |
string1 != string2 |
测试字符串 string1 是否与 字符串 string2 不相同 |
测试格式如下:
test string
只用string进行测试时,仅有一种格式 test,不存在用 "[" 和 "]" 括起来的命令格式。字符串比较时建议字符串变量使用双引号,即便变量为空,同样也要使用双引号。
比较两个字符串是否相等,详情如下:
Shell严格区分大小写:
在Shell中,字符串赋值和整数赋值没有却别,在整数比较时不要把字符串比较当做字符串使用。
使用的运算符不同,赋值变量也不同,这是Shell对变量的弱化造成的。
2.4、文件操作符
Shell提供文件操作符完成测试文件的各种操作。其格式为:
test file_operator file
或者为:
[ file_operator file ]
file_operator为文件操作符,file为文件名、目录名或文件路径等。
常见的文件操作符如下:
文件运算符 |
描述 |
-d file |
测试file是否为目录 |
-e file |
测试file是否存在 |
-f file |
测试file是否普通文件 |
-r file |
测试file是否是进程可读文件 |
-s file |
测试file长度是否不为0 |
-w file |
测试file是否进程可写文件 |
-x file |
测试file是否进程可执行文件 |
-L file |
测试file是否符号化链接 |
判断文件是目录还是文件:
列出所有文件,选取一个存在的文件和一个不存在的文件,分别进行测试:
测试文件权限的测试:
文件操作符中的可读、可写、可执行的权限判断经常和chmod命令联用,该命令可用于对文件进行增加或减少权限。
通过ll命令可看出,file.txt文件可读、可写,但不可执行,通过chmod命令给文件 file.txt 增加可执行权限,然后通过测试可以看出文件可执行了。
2.5、逻辑运算符
逻辑运算符用于测试多个条件是否为真或为假,或使用逻辑非测试单个表达式。运算符主要包括逻辑非、逻辑与、逻辑或运算符。
逻辑操作符详情如下:
逻辑操作符 |
描述 |
! expression |
如果expression为假,则测试结果为真 |
expression1 -a expression2 |
如果expression1和expression同时为真,则测试结果为真 |
expression1 -o expression2 |
如果expression1和expression2中有一个为真,则测试条件为真 |
其中 expression 为一个表达式,该表达式描述了一个测试条件。在逻辑表达式的运算过程中并不是所有的运算符都会被执行,如:
expr1 -a expr2 -a expr3
只有当表达式 expr1 为真时,才会接着测试 expr2 的值为真,同样,只有在 expr1 和 expr2 为真时,才会接着测试 expr3 的值是否为真。对于逻辑或的运算过程中也不是所有的语句都会被执行,如:
expr1 -o expr2 -o expr3
只要 expr1 为真,就不用测试 expr2 和 expr3,只有 expr 为假时才去判断表达式 expr2 和 expr3,同样,只有 expr1 和 expr2 同时为假时,才会去测试 expr3。
测试加上逻辑非操作符后的测试结果是反的:
逻辑与,都为真时,就为真;逻辑或,有一个为真时,就为真。
3、判断
判断,就是对语句中不同的条件进行测试,进而根据不同的条件执行不同的语句。if、then、else 语句用于判断给定的条件是否满足,可用于判断整数比较大小、字 符串操作、文件操作以及逻辑运算等方面,并根据测试条件的真假来选择相应的操作。
3.1、简单if结构
if语句是条件语句的一种形式,针对某种条件作出相应的处理。
if expression
then
...
fi
在使用这种简单的if结构时,需注意测试条件后如果没有";",则then语句要换行,否则会产生不必要的错误。
if expression; then
...
fi
新建 condition01.sh 脚本,详情如下:
#!/bin/bash
# 判断输入的数是否小于5
echo "Please input a num: "
read num
# 判断输入的是否小于5,小于5时将执行then语句
if [ "$num" -lt 5 ]; then
echo "输入的值小于5"
fi
执行结果如下:
新建 condition02.sh 脚本,详情如下:
#!/bin/bash
# 创建一个文件,测试是否创建成功,并测试文件权限
# 创建一个文件 con_test.txt
touch con_test.txt
# 判断文件 con_test.txt 是否创建成功
if [ -e con_test.txt ]
then
echo "file create successfully!"
fi
# 判断文件是否可读
if [ -r con_test.txt ]; then
echo "file can read"
fi
# 判断文件是否可写
if [ -w con_test.txt ]
then
echo "file can write"
fi
# 判断文件是否可执行
if [ -x con_test.txt ]
then
echo "file can execute"
fi
执行结果如下:
3.2、exit命令
判断语句和循环语句都涉及 exit 命令来控制程序和表达式的流程。其格式为:
exit status
status用 0 ~ 255 之间的数字表示,一般返回该状态值的同时伴随着脚本的退出,同退出状态一样,参数被保存在Shell变量$?中,可通过echo命令进行查询。需要注意的是,不能再终端运行exit命令,否则将会导致系统重启。
新建 exit01.sh 脚本,详情如下:
#!/bin/bash
# 判断用户输入的字符串是否为空
# 提示输入字符串
echo "Please input a string:"
read str
# 判断输入的字符串是否为空,为空是执行then后面的命令
if [ -z "$str" ]; then
echo "input is null!"
exit 1
fi
执行过程如下:
脚本 exit01.sh 先输入一个字符串,退出状态为0,表示脚本输入的字符串不为空,没有执行then中的语句,然后输入了一个空字符串,返回提示信息,同时返回一个退出状态为1,该退出状态值是在脚本中设置的,不是系统默认的退出状态值。
3.3、if/else结构
if/else命令是双向选择语句,当用户执行脚本时,若不满足if后的表达式,会执行else后命令。首先判断if后面的表达式,若表达式的退出状态为0,则执行then和else中间的语句,若表达式的退出状态为非0,则执行else和fi中的语句。then 和 else、else 和 fi 中间的语句可以是单个命令,也可是多个命令。结构为:
if expression
then
command1
...
commandN
else
command1
...
commandN
fi
新建 condition03.sh 脚本,详情如下:
#!/bin/bash
# 判断输入的文件名是否有对应的文件是否存在
# if语句用于判断输入的文件是否不存在,不存在执行then和else间的命令
if [ ! -e "$1" ]
then
echo "file $1 do not exits."
exit
# 输入的文件存在时,执行 else 和 fi 间的命令
else
echo "file $1 exits."
fi
执行结果如下:
首先用变量 $1 来存储用户输入的字符串,该字符串用于表示文件名,然后通过文件操作符来判断输入的文件名对应的文件是否不存在于当前的目录中,若不存在,则输出当前文件不存在且返回一个状态值1。
删除文件示例,新建 rm_example.sh 脚本,详情如下:
#!/bin/bash
# 用于删除一个文件并判断是否执行了该操作
echo "请输入要删除的文件:"
read filename
if rm -rf "$filename"
then
echo " $filename 删除成功 "
else
echo " $filename 删除失败 "
fi
执行结果如下:
3.4、if/else语句嵌套
if/else结构只能判断两个条件,若需要同时判断三个或三个以上的条件时,可使用if/else语句嵌套,还可使用 if/elif/else 和 case命令。
先看 if/else语句嵌套,其命令的标准结构如下:
if expression01
then
if expression02
then
...
else
...
fi
else
if expression03
then
...
else
...
fi
fi
新建 condition04.sh 文件,详情如下:
#!/bin/bash
# 检查输入的字符串是否是当前目录的文件名
# 输入是否空
if [ "$1" ]
then
echo "输入参数不为空"
# 判断当前目录是否存在该文件
if [ -e "$1" ]
then
echo "$1 exits."
else
echo "$1 not exits."
fi
else
echo "输入参数为空"
fi
执行结果如下:
3.5、if/elif/else语句嵌套
使用if/else嵌套在Shell编程过程中,容易漏掉then或fi而产生错误,if/elif/else结构针对某一事件的多种情况进行处理。通常表现为"如果满足某种条件,则进行某种处理,否则接着判断另一个条件,直到找到满足的条件,然后执行相应的处理"。语法格式为:
if expression01
then
...
elif expression02
then
...
elif expression0N
then
...
else
...
fi
if/elif/else结构,fi只出现一次。
#!/bin/bash
echo "Please input a score: "
read num
if [ "$num" -lt 0 -o "$num" -gt 100 ]; then
echo " input error "
else
if [ "$num" -ge 0 -a "$num" -lt 30 ]
then
echo "$num is E"
elif [ "$num" -ge 30 -a "$num" -lt 60 ]
then
echo "$num is D"
elif [ "$num" -ge 60 -a "$num" -lt 70 ]
then
echo "$num is C"
elif [ "$num" -ge 70 -a "$num" -lt 85 ]
then
echo "$num is B"
else
echo "$num is A"
fi
fi
执行结果如下:
3.6、case结构
case结构同样可用于多分支选择语句,常用来根据表达式的值选择要执行的语句,该命令一般格式为:
case variable in
value1)
...
command1;;
value2)
...
command2;;
...
valueN)
...
commandN;;
*)
...
commandE;;
esac
case结构的变量值 variable 与 value1 ... valueN 等进行逐一比较,直到找到匹配的值。若与其匹配,将执行其后的命令,遇到双分号则跳到 esac 后的语句执行,若没有找到与变量值 variable 匹配的值,脚本将执行默认值 "*)" 后的命令,直至 ";;" 为止。
注意:value1 与 value2 的值必须是常量或正则表达式,所以,使用case命令有时无法对if/else语句嵌套和对if/elif/else结构进行改写,只有当两个结构的判断条件匹配某常量或正则表达式时才能使用case命令。
在Shell编程过程中,一般对于判断条件很少的可以if条件语句;在多个条件判断且判断条件为不等于某个具体常量或正则表达式时,用if/elif/else结构;对于多个判断条件且判断条件是某变量匹配某常量或正则表达式时,可用case结构。
新建case01.sh脚本,详情如下:
#!/bin/bash
# 输入一个数字(1~12), 然后显示对应月份的中文
# 提示输入月份
echo "input a month(1-12)"
read month
# 判断数字对应的月份
case $month in
1)
echo "一月份";;
2)
echo "二月份";;
3)
echo "三月份";;
4)
echo "四月份";;
5)
echo "五月份";;
6)
echo "六月份";;
7)
echo "七月份";;
8)
echo "八月份";;
9)
echo "九月份";;
10)
echo "十月份";;
11)
echo "十一月份";;
12)
echo "十二月份";;
*)
echo "$month is not in (1,12).";;
esac
执行结果如下:
4、运算符
4.1、算术运算符
Linux Shell中,算术运算符包括:+ (加运算)、- (减运算)、 (乘运算)、 / (除运算)、% (取余运算)、** (幂运算)。
执行结果如下:
使用算术运算符无法对字符串、文件的浮点型数进行计算,对于浮点型操作,需要用到专门的函数。
算术运算符可与赋值运算符"="联用,称为算术复合赋值运算符,详情如下:
运算符 |
案例 |
等价表达式 |
+= |
v+=5 |
v=v+5 |
-= |
v-=10 |
v=v-10 |
*= |
v*=5 |
v=v*5 |
/= |
v/=3 |
v=v/3 |
%= |
v%=5 |
v=v%5 |
案例如下:
4.2、位运算符
位运算符,通常用于整数间的运算,位运算符是针对整数在内存中存储的二进制数据流中的位进行操作。
位运算符:
运算符 |
举例 |
解释和value值 |
<<(左移) |
value=4<<2 |
4左移2位,value=16 |
>>(右移) |
value=8>>2 |
8右移2位,value=2 |
&(按位与) |
value=8&4 |
8按位与4,value=0 |
|(按位或) |
value=8|4 |
8按位或4,value=12 |
~(按位非) |
value=~8 |
按位非8,value=-9 |
^(按位异或) |
value=10^3 |
10按位异或3,value=9 |
按位与运算,只有两个二进制都为1时,结果才为1;
按位或运算,只要有一个二进制为1,则结果为1;
按位异或运算,两个二进制位数相同(同时为0或1)时,结果为0,否则为1;
按位取反,将二进制中的0修改为1,1修改为0。
复合运算符:
运算符 |
举例 |
等价表达式 |
<<= |
value<<=2 |
value=value<<2 |
>>= |
value>>=2 |
value=value>>2 |
&= |
value&=4 |
value=value&4 |
|= |
value|=4 |
value=value|4 |
^= |
value^=3 |
value=value^3 |
案例详情如下:
4.3、自增自减运算符
自增自减运算符,作用是自动将变量加1或减1。自增自检操作符主要包括前置自增(++variable)、前置自减(--variable)、后置自增(variable++)和后置自减(variable--)。
前置操作先改变变量的值,然后将改变的变量值交给表达式使用;后置变量是在表达式使用后再改变变量的值。
自增自减操作符的操作元只能变量,不能是常数或表达式,且该变量必须为整数型。
4.4、数字常量
Shell脚本或命令默认将数字以十进制的方式进行处理,若要是用其他进制的方式进行处理,则需对这个数字进行也定的标记或加前缀。
当使用 0 作为前缀时,表示八进制;当使用 0x 进行标记时,表示十六进制。
新建 constant.sh 脚本,详情如下:
#!/bin/bash
# 数字常量
# 默认进制表示方式:十进制
let "num=40"
echo "num=$num"
# 八进制表示方式:以0作为前缀
let "num2=040"
echo "num2=$num2"
# 十六进制表示方式:以0x作为前缀
let "num3=0x40"
echo "num3=$num3"
执行结果如下:
Shell编程中还可使用"num#"来表示不同的进制。新建 constant02.sh 脚本,详情如下:
#!/bin/bash
# num# 方式表示数字常量
# 二进制表示方式:2#
let "num=2#1101100110001101"
echo "num=$num"
# 八进制表示方式:8#
let "num2=8#50"
echo "num2=$num2"
# 十六进制表示方式:16#
let "num3=16#50"
echo "num3=$num3"
执行结果如下: