【shell笔记>脚本】使用结构化命令之条件控制

内容

  • 使用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  

conditiontest命令要测试的一系列参数和值。如果不写这个conditiontest返回非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命令的简便方式,它会参照一个值列表来检查单个变量的值。

关于结构化命令中循环,将在下次整理的笔记中阐述。

你可能感兴趣的:(【shell笔记>脚本】使用结构化命令之条件控制)