【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命令的简便方式,它会参照一个值列表来检查单个变量的值。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,587评论 18 139
  • 基础命令 主要的命令和快捷键 Linux系统命令由三部分组成:cmd + [options]+[operation...
    485b1aca799e阅读 1,085评论 0 0
  • 1.创建文件夹 !/bin/sh mkdir -m 777 "%%1" 2.创建文件 !/bin/sh touch...
    BigJeffWang阅读 10,015评论 3 53
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,350评论 0 17
  • 通过上一个小节的学习,我们已经掌握分子的定义,分子指的是构成物质的一种微粒。像二氧化碳、氢气、水等这些物质都是由分...
    真真卒迹阅读 803评论 0 0