本章内容:
- 使用 if-then 语句
- 嵌套 if 语句
test
命令- 复合条件测试
- 使用双方括号和双括号
case
命令
有一类命令允许脚本根据条件跳过部分命令,改变执行流程。这样的命令通常被称为结构化命令( structured command )。其中最基本的结构化命令是 if-then 语句。
if command
then
commands
fi
bash shell 的 if 语句会运行 if 之后的命令。
如果该命令的退出状态码为 0 (命令成功运行),那么位于 then 部分的命令就会被执行。
如果退出状态码是其他值,则 then 部分的命令不会被执行,bash shell 会接着处理脚本中的下一条命令。
fi 语句用来表示 if-then 语句到此结束。
应用示例:
# 1.脚本内容。(这里第一个if块使用了存在的命令;第二个if块使用不存在的命令。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
if whoami
then
echo "ok"
fi
echo -e "\n============\n"
if notCommand
then
echo "ok"
fi
# 2.执行脚本。(第一个if块顺利执行then;第二个if块未执行then。)
[root@VM-8-11-centos testdir]# ./test.sh
root
ok
============
./test.sh: line 9: notCommand: command not found
当 if 语句中的命令返回非 0 退出状态码时,bash shell 会执行 else 部分中的命令。
if command
then
commands
else
commands
fi
# 1.脚本内容。(if块使用不存在的命令。)
[root@VM-8-11-centos testdir]# cat ./test.sh
#!/bin/bash
if notCommand
then
echo "ok"
else
echo "use the correct command!"
fi
# 2.执行脚本。(if退出码非0,执行else块。)
[root@VM-8-11-centos testdir]# ./test.sh
./test.sh: line 2: notCommand: command not found
use the correct command!
有时需要在脚本中检查多种条件。对此,可以使用嵌套的 if-then 语句。
if command1
then
commands
elif command2
then
commands
else
commands
fi
# 1.脚本内容。(if不成立,elif都成立。 -> 提示:依次执行,只有第一个退出状态码0的then语句才会被执行。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
if notCommand
then
echo "if block"
elif whoami
then
echo "elif1 block"
elif pwd
then
echo "elif2 block"
else
echo "else block"
fi
# 2.执行脚本。(只有第一个elif的then被执行到了。 -> 提示:如果if和elif退出状态码都非0,才会执行else)
[root@VM-8-11-centos testdir]# ./test.sh
./test.sh: line 2: notCommand: command not found
root
elif1 block
test
命令可以在 if-then 语句中测试不同的条件。如果test
命令中列出的条件成立,那么就会退出并返回退出状态码 0 。
if test condition
then
commands
else
commands
fi
test
命令的 condition 部分,则它会以非 0 的退出状态码退出并执行 else 代码块语句。test
命令会测试该条件。test
命令:if [ condition ]
then
commands
fi
使用
test
命令最常见的情形是对两个数值进行比较。
test
命令的数值比较功能:比较 | 描述 |
---|---|
n1 -eq n2 | 检查 n1 是否等于 n2。 |
n1 -ge n2 | 检查 n1 是否大于或等于 n2。 |
n1 -gt n2 | 检查 n1 是否大于 n2。 |
n1 -le n2 | 检查 n1 是否小于或等于 n2。 |
n1 -lt n2 | 检查 n1 是否小于 n2。 |
n1 -ne n2 | 检查 n1 是否不等于 n2 |
# 1.脚本内容。(定义两个整数值进行测试比较。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
num1=10
num2=11
#
if [ $num1 -gt 5 ]
then
echo "$num1 is greater than 5."
fi
#
if [ $num1 -eq $num2 ]
then
echo "The values are equal."
else
echo "The values are different."
fi
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
10 is greater than 5.
The values are different.
echo
),但它们在条件测试下无法正常工作。测试条件还允许比较字符串值。
test
命令的字符串比较功能:比较 | 描述 |
---|---|
str1 = str2 | 检查 str1 是否和 str2 相同。 |
str1 != str2 | 检查 str1 是否和 str2 不同。 |
str1 < str2 | 检查 str1 是否小于 str2 。 |
str1 > str2 | 检查 str1 是否大于 str2。 |
-n str1 | 检查 str1 的长度是否不为 0。 |
-z str1 | 检查 str1 的长度是否为 0。 |
4.2.1 字符串相等性
字符串的相等或不等条件不言自明。
# 1.脚本内容。(比较两个字符串是否相同。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
str1="hello"
#
if [ "hello" = $str1 ]
then
echo "euqal."
else
echo "not equal."
fi
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
euqal.
4.2.2 字符串顺序
要测试一个字符串是否大于或小于另一个字符串就开始变得棘手了。
sort
命令所采用的不同。# 1.脚本内容。(比较时,没有对大于号进行转义。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
str1=soccer
str2=zorbfootball
#
if [ $str1 > $str2 ]
then
echo "$str1 is greater than $str2 ."
else
echo "$str1 is less than $str2 ."
fi
# 2.执行脚本。(比较结果不符合预期,并且把大于号当作了重定向符号生成了新文件。)
[root@VM-8-11-centos testdir]# ./test.sh
soccer is greater than zorbfootball .
[root@VM-8-11-centos testdir]# ls z*
zorbfootball
# 1.移除文件。
[root@VM-8-11-centos testdir]# rm -rf zorbfootball
# 2.修改脚本内容。(添加转义。)
[root@VM-8-11-centos testdir]# vim test.sh
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
str1=soccer
str2=zorbfootball
#
if [ $str1 \> $str2 ]
then
echo "$str1 is greater than $str2 ."
else
echo "$str1 is less than $str2 ."
fi
# 3.执行脚本。(比较结果符合预期。)
[root@VM-8-11-centos testdir]# ./test.sh
soccer is less than zorbfootball .
# 4.是否又重定向生成了新的文件。
[root@VM-8-11-centos testdir]# ls z*
ls: cannot access z*: No such file or directory
# 1.sort排序时,优先出现小写字母。
[root@VM-8-11-centos testdir]# cat 1.txt
Soccer
soccer
[root@VM-8-11-centos testdir]# sort 1.txt
soccer
Soccer
[root@VM-8-11-centos testdir]# vim test.sh
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
str1=Soccer
str2=soccer
#
if [ $str1 \> $str2 ]
then
echo "$str1 is greater than $str2 ."
else
echo "$str1 is less than $str2 ."
fi
# 2.执行脚本。(在比较测试中,大写字母被认为是小于小写字母的。)
[root@VM-8-11-centos testdir]# ./test.sh
Soccer is less than soccer .
sort
命令使用的是系统的语言环境设置中定义的排序顺序。对于英语,语言环境设置指定了在排序顺序中小写字母出现在大写字母之前。test
命令和测试表达式使用标准的数学比较符号来表示字符串比较。而用文本代码来表示数值比较。4.2.3 字符串大小
-n 和 -z 可以很方便地用于检查一个变量是否为空。
# 1.脚本内容。
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
str1=""
#
if [ -z "$str1" ]
then
echo "$str1 is empty."
else
echo "$str1 is not empty."
fi
#
if [ -n "$str1" ]
then
echo "$str1 is not empty."
else
echo "$str1 is empty."
fi
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
is empty.
is empty.
在shell中,引用变量时,加不加双引号是有区别的:
1.如果不加双引号,shell会将变量展开为其值,并将其作为一个单词处理。这意味着,如果变量的值包含空格或其他特殊字符,这些字符会被解释为单词分隔符或特殊字符,可能会导致意外的结果。
例如,假设有一个变量`var="hello world"`,如果不加双引号,使用`echo $var`命令输出的结果将是两个单词`hello`和`world`,而不是一个单词`hello world`。
2.如果加上双引号,shell会将变量展开为其值,并将其作为一个整体处理。这意味着,变量的值中的空格和其他特殊字符会被保留,不会被解释为单词分隔符或特殊字符。
例如,使用`echo "$var"`命令输出的结果将是一个单词`hello world`,而不是两个单词`hello`和`world`。
结论:因此,为了避免意外的结果,建议在引用变量时加上双引号。
最后一类比较测试很有可能是 shell 编程中最为强大且用得最多得比较形式。它允许测试 Linux 文件系统中文件和目录的状态。
test
命令的文本比较功能:比较 | 描述 |
---|---|
-d file | 检查 file 是否存在且为目录。 |
-e file | 检查 file 是否存。 |
-f file | 检查 file 是否存在且为文件。 |
-r file | 检查 file 是否存在且可读。 |
-s file | 检查 file 是否存在且非空。 |
-w file | 检查 file 是否存在且可写。 |
-x file | 检查 file 是否存在且可执行。 |
-O file | 检查 file 是否存在且属当前用户所有。 |
-G file | 检查 file 是否存在且默认组与当前用户相同。 |
file1 -nt file2 | 检查 file1 是否比 file2 新。 |
file1 -ot file2 | 检查 file1 是否比 file2 旧。 |
# 1.脚本内容。(需求:如果目标文件为空则进行删除。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
# Check if a file is empty.
fileName=/home/tmp/1.txt
#
echo
echo "checking if $fileName file is empty... "
# if exists
if [ -f $fileName ]
then
# is empty.
if [ -s $fileName ]
then
echo "$fileName file exists and has data in it."
echo "will not remove this file."
else
echo "$fileName file exists, but is empty."
echo "deleting this file..."
rm -rf $fileName
echo "$fileName file, successfully deleted!"
fi
#
else
echo "The $fileName file does not exist."
fi
# 2.被操作文件为非空文件。
[root@VM-8-11-centos testdir]# ls -sh /home/tmp/1.txt
4.0K /home/tmp/1.txt
# 3.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
checking if /home/tmp/1.txt file is empty...
/home/tmp/1.txt file exists and has data in it.
will not remove this file.
if-then 语句允许使用布尔逻辑将测试条件组合起来。
布尔运算符 AND 来组合两个条件(都必须满足):[ condition ] && [ condition ]
布尔运算符 OR 来组合两个条件(任意条件满足):[ condition ] || [ condition ]
应用示例:
# 1.脚本内容。(如果$HOME目录存在且该目录下有名为newfile的可写文件,则提示写入。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
if [ -d $HOME ] && [ -w $HOME/newfile ]
then
echo "the file exists and you can write to it."
else
echo "you cannot write to the file."
fi
# 2.当前无此文件。
[root@VM-8-11-centos testdir]# ls -l $HOME/newfile
ls: cannot access /root/newfile: No such file or directory
[root@VM-8-11-centos testdir]# ./test.sh
you cannot write to the file.
# 3.创建文件,再次执行脚本测试。
[root@VM-8-11-centos testdir]# touch $HOME/newfile
[root@VM-8-11-centos testdir]# ls -l $HOME/newfile
-rw-r--r-- 1 root root 0 Jun 11 10:32 /root/newfile
[root@VM-8-11-centos testdir]# ./test.sh
the file exists and you can write to it.
# 4.清理操作。
[root@VM-8-11-centos testdir]# rm -rf $HOME/newfile
bash shell 还提供了 3 个可在 if-then 语句中使用的高级特性。
单括号允许在 if 语句中使用子 shell。
在 bash shell 执行命令之前,会先创建一个子 shell ,然后在其中执行命令。
如果命令成功结束,则退出状态码会被设为 0 ,then 部分就会被执行。否则,不执行 then 部分的命令。
应用示例:
# 1.脚本内容。(使用子shell进行测试。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
echo $BAHS_SUBSHELL
#
if (echo $BASH_SUBSHELL)
then
echo "successsfully."
else
echo "not successfully."
fi
# 2.执行脚本。(1表示使用了子shell。)
[root@VM-8-11-centos testdir]# ./test.sh
1
successsfully.
双括号命令允许在比较过程中使用高级数学表达式。相较于
test
命令进行比较时,双括号命令提供了更多的数学符号。
test
命令使用的标准数学运算符,还有:符号 | 描述 |
---|---|
val ++ | 后增。 |
val – | 后减。 |
++ val | 先增。 |
– val | 先减。 |
! | 逻辑求反。 |
~ | 位求反。 |
** | 幂运算。 |
<< | 左位移。 |
>> | 右位移。 |
& | 位布尔 AND。 |
| | 位布尔 OR。 |
&& | 逻辑 AND。 |
|| | 逻辑 OR。 |
# 1.脚本内容。(num1的平方是否大于90,并将该值的平方赋值给num2)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
num1=10
#
if (( $num1 ** 2 > 90 ))
then
(( num2=$num1 ** 2))
echo "the suqare of $num1 is $num2."
echo "which is greater than 90."
fi
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
the suqare of 10 is 100.
which is greater than 90.
双方括号命令提供了针对字符串比较的高级特性。
test
命令使用的标准字符串比较,还提供了 test
命令所不具备的另一个特性——模式匹配。# 1.脚本内容。(通配符匹配)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
#
echo $BASH_VERSION
#
if [[ $BASH_VERSION == 4.* ]]
then
echo "using version 4 series."
fi
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
4.2.46(2)-release
using version 4 series.
尝试计算一个变量的值,在一组可能的值中寻找特定值。case 命令会采用列表格式来检查变量的多个值,就无须再写大量的 elif 语句来检查同一个变量的值了。
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
# 1.脚本内容。(判断当前用户类型。)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
case $USER in
"jan" | "lucy")
echo "$USER is a ordinary user."
;;
"root")
echo "$USER is the administrator."
;;
*)
echo "$USER It's a different type of account."
esac
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
root is the administrator.
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。