内容
- 使用if-then语句
- 嵌套if语句
- test命令
- 复合条件测试
- 使用双方括号和双括号
- case命令
许多程序要求对shell脚本中的命令施加一些逻辑流程控制。而某些命令会根据条件判断执行相应的命令,这样的命令通常叫做结构化命令。从概念上理解,结构化命令是shell脚本的逻辑结构,不像顺序执行shell脚本,而是有组织地执行命令以应对复杂任务需求。
if-then语句
最基本的结构化命令是if-then语句,它的格式如下:
if command
then
commands
fi
注意,在其他编程语言中,if
语句之后的对象是一个等式,等式的结果为TRUE
或者FALSE
,但是bash shell中的if
语句是运行if
后面的命令,如果该命令的退出状态码是0(命令成功执行),则运行then
语句后面的命令。fi
表示if
语句到此结束。
下面是一个简单的例子:
wsx@wsx-ubuntu:~/script_learn$ cat test1.sh
#! /bin/bash
# testing the if statement
if pwd
then
echo "It worked"
fi
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test1.sh
wsx@wsx-ubuntu:~/script_learn$ ./test1.sh
/home/wsx/script_learn
It worked
这个例子中在判断成功执行pwd
命令后,执行输出文本字符串。
大家可以尝试把pwd
命令改成随便乱打的字符试试结果。它会显示报错信息,then
后面的语句也不会执行。
if-then语句的另一种形式:
if command; then
commands
fi
在then部分,我们可以使用多个命令(从格式中command结尾有没有s也可以看出)。
我们再来一个例子:在if
语句中用grep
命令在/etc/passwd
文件中查找某个用户名当前是否在系统上使用。如果有用户使用了哪个登录名,脚本会显示一些文本信息并列出该用户HOME目录的bash文件。
wsx@wsx-ubuntu:~/script_learn$ cat test3.sh
#!/bin/bash
# testing multiple commands in the then section
#
testuser=wsx
#
if grep $testuser /etc/passwd
then
echo "This is my first command"
echo "This is my second command"
echo "I can even put in other commands besides echo:"
ls -a /home/$testuser/.b*
fi
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test3.sh
wsx@wsx-ubuntu:~/script_learn$ ./test3.sh
wsx:x:1000:1000:wsx,,,:/home/wsx:/bin/bash
This is my first command
This is my second command
I can even put in other commands besides echo:
/home/wsx/.bash_history /home/wsx/.bashrc
/home/wsx/.bash_logout /home/wsx/.bashrc-anaconda3.bak
如果设置的用户名不存在,那么就没有输出。那么如果在这里显示的一些消息可以说明用户名在系统中未找到,这样可能就会显得更友好。所以接下来看看if-then-else
语句。
if-then-else语句
我相信意思非常容易理解,这里较之前我们添加了一个else
块来处理if
中命令没有成功执行的步骤。格式为:
if command
then
commands
else commands
fi
嵌套if
有时我们需要检查脚本代码中的多种条件,可以是用嵌套的if-then
语句。
处理一个例子:检查/etc/passwd
文件中是否存在某个用户名以及该用户名的目录是否存在。
wsx@wsx-ubuntu:~/script_learn$ cat test5.sh
#!/bin/bash
# Testing nested ifs
#
testuser=NoSuchUser
#
if grep $testuser /etc/passwd
then
echo "The user $testuser exits on this system."
else
echo "The user $testuser does not exit on this system."
if ls -d /home/$testuser/
then
echo "However, $testuser has a directory."
fi
fi
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test5.sh
wsx@wsx-ubuntu:~/script_learn$ ./test5.sh
The user NoSuchUser does not exit on this system.
ls: 无法访问'/home/NoSuchUser/': 没有那个文件或目录
可以使用else
部分的另一种形式:elif
。这样我们就不再用书写多个if-then
语句了。在其他语言中,有的是用elif
的形式,有的使用else if
等形式。面对相同内含在不同语言中不同的表示方式,我们需要有意识地区别,以免接触的东西多了可能各种语言代码串写喔。
if command1
then
commands
elif command2
then
more commands
fi
这种表示方式逻辑更为清晰,但是也有点容易让写的人搞混。其实可以看到一个if
对应一个fi
。这是一个大的嵌套if
结构。
记住,在elif
语句中,紧跟其后的else
语句属于elif
代码块,而不是属于if-then
代码块。
test命令
到此为止,我们很清楚if
后面跟着的是普通的shell命令,那么我们需要测试其他条件怎么办呢?
test
命令提供了在if-then
语句中测试不同条件的途径。如果test
命令中列出的条件成立,test
命令就会退出并返回状态码0。这样if-then
语句就与其他编程语言中的if-then
语句以类似的方式工作了。
test命令格式:
test condition
condition
是test
命令要测试的一系列参数和值。如果不写这个condition
,test
返回非0,if
语句跳转到else
进行执行。
bash shell提供了一种条件测试方法,无需在if-then
语句中声明test
命令。
if [ condition ]
then commands
fi
这跟我们其他的编程习惯非常接近。建议使用这种方式。
如果使用test
命令,需要记住的是各种条件参数。
数值比较
比较 | 描述 |
---|---|
n1 -eq n2 | (n1)等于(n2) |
n1 -ge n2 | 大于或等于 |
n1 -gt n2 | 大于 |
n1 -le n2 | 小于或等于 |
n1 -lt n2 | 小于 |
n1 -ne n2 | 不等于 |
字符串比较
比较 | 描述 |
---|---|
str1 = str2 | (str1与str2比较)相同 |
str1 != str2 | 不同 |
str1 < str2 | 小 |
str1 > str2 | 大 |
-n str1 | 检查string1的长度非0 |
-z str1 | 检查string1的长度是否为0 |
注意,大于和小于号必须转义;大于和小于顺序和sort命令所采用的不同。
文件比较
比较 | 描述 |
---|---|
-d file | 检查file是否存在并是一个目录 |
-e file | ~是否存在 |
-f file | ~是否存在并是一个文件 |
-r file | ~是否存在并可读 |
-s file | ~是否存在并非空 |
-w file | ~是否存在并可写 |
-x file | ~是否存在并可执行 |
-O file | ~是否存在并属当前用户所有 |
-G file | ~是否存在并且默认组与当前用户相同 |
file1 -nt file2 | 检查file1是否比file2新 |
file1 -ot file2 | 检查file1是否比file2旧 |
复合条件测试
if-then
语句允许我们使用布尔逻辑来组合测试。可用
- [ condition1] && [ condition2]
- [ condition1] || [ condition2]
if-then的高级特性
- 用于数学表达式的双括号
- 用于高级字符串处理功能的双方括号
双括号
命令格式:
(( expresiion ))
expression
可以是任意的数学赋值或比较表达式。除了test
命令使用的标准数学运算符,下面列出了一些其他的:
符号 | 描述 |
---|---|
val ++ | 后增 |
val -- | 后减 |
++ val | 先增 |
-- val | 先减 |
! | 逻辑取反 |
~ | 位求反 |
** | 幂运算 |
<< | 左位移 |
>> | 右位移 |
& | 位布尔和 |
| | 位布尔或 |
&& | 逻辑和 |
|| | 逻辑或 |
看一个例子:
wsx@wsx-ubuntu:~/script_learn$ cat test23.sh
#!/bin/bash
# using doble parenthesis
#
val1=10
#
if (( $val1 ** 2 > 90 ))
then
(( val2 = $val1 ** 2 ))
echo "The square of $val1 is $val2"
fi
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test23.sh
wsx@wsx-ubuntu:~/script_learn$ ./test23.sh
The square of 10 is 100
双方括号
双方括号命令提供了针对字符串比较的高级特性。命令格式如下:
[[ expression ]]
双方括号里的expression
使用了test
命令中采用的标准字符串比较。但它提供了test
没有提供的一个特性——模式匹配。
在模式匹配中,可以定义一个正则表达式来匹配字符串值。
wsx@wsx-ubuntu:~/script_learn$ cat test24.sh
#! /bin/bash
# using pattern matching
#
if [[ $USER == r* ]]
then
echo "Hello $USER"
else
echo "Sorry, I do not know you"
fi
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test24.sh
wsx@wsx-ubuntu:~/script_learn$ ./test24.sh
Sorry, I do not know you
上面一个脚本中,我们使用了双等号。双等号将右边的字符串视为一个模式,并将其应用模式匹配规则。
case命令
有了case
命令,就不需要写出所有的elif
语句来不停地检查同一个变量的值了。case
命令会采用列表格式来检查单个变量的多值。
下面是两个脚本实现相同功能进行对比:
if语句:
wsx@wsx-ubuntu:~/script_learn$ cat test25.sh
#!/bin/bash
# looking for a possible value
#
if [ $USER = "rich" ]
then
echo "Welcome $USER"
echo "Please enjoy you visit"
elif [ $USER = "barbara" ]
then
echo "Welcome $USER"
echo "Please enjoy you visit"
elif [ $USER = "testing" ]
then
echo "Special testing account"
elif [ $USER = "jessica" ]
then
echo "Do not forget to logout when you're done"
case语句:
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac
上面的实例可以用case
语句表示为:
wsx@wsx-ubuntu:~/script_learn$ cat test26.sh
#!/bin/bash
# using the case command
#
case $USER in
rich | barbara)
echo "Welcome, $USER"
echo "Please enjoy your visits";;
testing)
echo "Special testing account";;
jessica)
echo "Do not forget to log off whe you're done";;
*)
echo "Sorry, you are not allowed here";;
esac
wsx@wsx-ubuntu:~/script_learn$ chmod u+x test26.sh
wsx@wsx-ubuntu:~/script_learn$ ./test26.sh
Sorry, you are not allowed here
case
命令会将指定的变量与不同模式进行比较。如果变量和模式是匹配的,那么shell会执行为该模式指定的命令。可以通过竖线操作符在一行中分隔出多个模式。星号会捕获所有与已知模式不匹配的值。注意双分号的使用。
小结
最基本的命令是
if-then
语句;可以拓展
if-then
语句为if-then-else
语句;可以将
if-then-else
语句通过elif
语句连接起来;在脚本中,我们需要测试一种条件而不是命令时,比如数值、字符串内容、文件或目录的状态,
test
命令提供了简单方法;方括号是
test
命令统一的特殊bash命令;双括号使用另一种操作符进行高级数学运算双方括号允许高级字符串模式匹配运算;
case
命令是执行多个if-then-else
命令的简便方式,它会参照一个值列表来检查单个变量的值。
关于结构化命令中循环,将在下次整理的笔记中阐述。