1、 结构化命令
上一次我们学习了shell脚本的一些基础知识,包括环境变量、重定向、数学运算、退出脚本的方式等,想了解的可以戳这个: shell脚本基础
之前,在我们的示例shell脚本里,shell按照命令在脚本中出现的顺序依次进行处理。然而有时候,我们需要对shell脚本中的命令施加一些逻辑流程控制。有一类命令会根据条件使脚本跳过某些命令。这样的命令通常称为结构化命令,它允许我们改变程序执行的顺序。下面,我们学习一下常见的结构化命令 :
2、if-then语句
一般格式如下 :

if command
then commands
fi

bash shell的if语句会运行if后面的那个命令。如果该命令的退出状态码是0即该命令成功运行,位于then部分的命令就会被执行。如果该命令的退出状态码是其他值,then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。fi语句用来表示if-then语句到此结束。
示例 : 判断用户名当前是否在系统上使用,如果有用户使用了那个登录名,脚本会显示一些文本信息并列出该用户HOME目录的bash文件。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
# testing if-then
username=Miya
if grep $username /etc/passwd
thenecho "$username exits!"ls -a /home/$username/.b*
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Miya:x:1026:1026::/home/Miya:/bin/bash
Miya exits!
/home/Miya/.bash_logout  /home/Miya/.bash_profile  /home/Miya/.bashrc

在if-then语句中,不管命令是否成功执行,你都只有一种选择。如果命令返回一个非零退出状态码,bash shell会继续执行脚本中的下一条命令。当这种情况出现时,如果我们想执行另一组命令怎么办, if-then-else语句可以做到。

3、if-then-else语句

if command
then commands
else commands
fi

当if语句中的命令返回退出状态码0时,then部分中的命令会被执行。当if语句中的命令返回非零退出状态码时,bash shell会执行else部分中的命令。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
# testing if-then
username=$1
if grep $username /etc/passwd
thenecho "$username exits!"ls -a /home/$username/.b*
elseecho "$username is not exits !"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh Miya
Miya:x:1026:1026::/home/Miya:/bin/bash
Miya exits!
/home/Miya/.bash_logout  /home/Miya/.bash_profile  /home/Miya/.bashrc[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh haha
haha is not exits !

如果我们需要多次判断,可以采用嵌套if-then语句,但其实我们有更便于理解和使用的方法:

if command1
then commands
elif command2
then more commands
fi

elif语句行提供了另一个要测试的命令,这类似于原始的if语句行。如果elif后命令的退出状态码是0,则bash会执行第二个then语句部分的命令。
示例 : 判断存在某个用户名以及该用户的目录是否存在。

[root@relay3.mobvista.com:101.251.254.6 shell]#userdel Miya     //删除了Miya用户
[root@relay3.mobvista.com:101.251.254.6 shell]#grep Miya /etc/passwd
[root@relay3.mobvista.com:101.251.254.6 shell]#ls /home/* | grep Miya          //家目录依旧存在
/home/Miya:[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
# testing if-then
username=$1
if grep $username /etc/passwd
thenecho "$username exits!"ls -a /home/$username/.b*
elif    ls -d /home/$username
thenecho -n "$username is not exits!"echo " But $username has directory!"
elseecho "$username is not exits and doesn't have directory!"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh root
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
root exits!
ls: cannot access /home/root/.b*: No such file or directory
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh Miya
/home/Miya
Miya is not exits! But Miya has directory!
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh haha
ls: cannot access /home/haha: No such file or directory
haha is not exits and doesn't have directory!

需要注意的是,运行if语句中的命令所生成的消息依然会显示在脚本的输出中。有时我们可能不想看到信息,或者我们不想在脚本输出中显示一些错误消息,这个时候我们就需要将脚本的输出重定向到Linux系统的不同位置,这里大致做个演示,具体参考链接 : shell脚本的输入输出和重定向

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
# testing if-then
username=$1
if grep $username /etc/passwd > /dev/null
thenecho "$username exits!"ls -a /home/$username/.b* 2> /dev/null      //标准错误重定向到/dev/null,这是一个特殊的设备文件,它丢弃一切写入其中的数据
elif    ls -d /home/$username   2> /dev/null
thenecho -n "$username is not exits!"echo " But $username has directory!"
elseecho "$username is not exits and doesn't have directory!"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh root
root exits!
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh Miya
/home/Miya
Miya is not exits! But Miya has directory!
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh haha
haha is not exits and doesn't have directory!

4、if条件测试
到目前为止,在if语句中看到的都是普通shell命令。为了能测试命令退出状态码之外的条件,bash shell提供了另一种条件测试方法 :

if [ condition ]         //方括号定义了测试条件。
then commands
fi

注意,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错。
可以判断三类条件:数值、字符串、文件

(1)数值比较

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
var1=7
var2=10
if [ $var1 -gt 5 ]
thenecho "$var1 is bigger than 5!"
fi
if [ $var1 -eq $var2 ]
thenecho "The values are equal!"
elseecho "The values are different!"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
7 is bigger than 5!
The values are different!

当条件测试涉及浮点数时会出错:

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
var1=7.77
echo "The value is $var1!"
if [ $var1 -gt 5 ]
thenecho "The $var1 is bigger than 5!"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
The value is 7.77!
test.sh: line 4: [: 7.77: integer expression expected

(2)字符串比较

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
testuser=root
if [ $USER = $testuser ]
thenecho "Welcome $testuser!"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Welcome root!

判断字符串是否相等很显而易见,但是判断字符串大小时要格外注意:

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
string1=asdfg
string2=hjk
if [ $string1 > $string2 ]
thenecho "$string1 is more than $string2!"
elseecho "$string1 is less than $string2"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
asdfg is more than hjk!
[root@relay3.mobvista.com:101.251.254.6 shell]#ll hjk
-rw-r--r--. 1 root root 0 Jul 31 12:09 hjk

这个脚本中用了大于号,没有出现错误,但结果是错的。脚本把大于号解释成了输出重定向。因此,它创建了一个名为hjk的文件。由于重定向的顺利完成,if语句便以为所有命令都成功结束了,于是输出了then语句中内容。正确格式如下 :

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
string1=asdfg
string2=hjk
if [ $string1 \> $string2 ]
thenecho "$string1 is more than $string2!"
elseecho "$string1 is less than $string2"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
asdfg is less than hjk

此外,比较测试中使用的是标准的ASCII顺序,根据每个字符的ASCII数值来决定排序结果,大写字母被认为是小于小写字母的。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
string1=Test
string2=test
if [ $string1 \> $string2 ]
thenecho "$string1 is more than $string2!"
elseecho "$string1 is less than $string2"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Test is less than test

(3)文件比较

if-then语句还允许使用布尔逻辑来组合测试,逻辑与和逻辑或 :
 [ condition1 ] && [ condition2 ]
 [ condition1 ] || [ condition2 ]

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
if [ -d $HOME ] && [ -w $HOME/test ]
thenecho "$HOME/test exits and you can write"
elseecho "You cannot write to $HOME/test "
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
You cannot write to /root/test
[root@relay3.mobvista.com:101.251.254.6 shell]#touch /root/test
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
/root/test exits and you can write

(4)if-then的高级特性
双括号命令允许你在比较过程中使用高级数学表达式。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
var1=10
if (( $var1 ** 2 > 90))      //双括号中表达式里的大于号也不需要转义
then(( var2 = $var1 ** 2))echo "The square of $var1 is $var2"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
The square of 10 is 100

双方括号命令提供了针对字符串比较的高级特性。在模式匹配中,可以定义一个正则表达式来匹配字符串值。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
if [[ $USER == r* ]]
thenecho "Welcome $USER!"
fi[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Welcome root!

5、case语句

case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac

case命令会将指定的变量与不同模式进行比较。如果变量和模式是匹配的,那么shell会执行为该模式指定的命令。可以通过竖线操作符在一行中分隔出多个模式模式。星号会捕获所有与已知模式不匹配的值。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
pet=$1
case $pet in
dog|cat)echo $pet is lovely;;
pig)echo $pet is fat;;
*)echo error;;
esac[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh dog
dog is lovely
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh duck
error

6、for语句

for var in list
do
commands
done

在list参数中,你需要提供迭代中要用到的一系列值。for命令最基本的用法就是遍历for命令自身所定义的一系列值。
示例: 需要注意的有两处,系列值中包含空格的要用双引号(" "),包含单引号的需要转义或者用双引号。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
for list in Beijing Tokyo "Los Angeles" Xi\'an   //注意空格和单引号
doecho "Next station is $list"
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Next station is Beijing
Next station is Tokyo
Next station is Los Angeles
Next station is Xi'an

还要提到的一点是,IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下,bash shell会将下列空格、制表符、换行符当作字段分隔符。我们也可以在shell脚本中临时更改IFS值来限制被bash shell当作字段分隔符的字符。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat states
Beijing Tokyo Florida Alaska
[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
# reading values from a file
file="states"
IFS=$'\n'        //指定分隔符为换行符
for state in $(cat $file)
doecho "Visit beautiful $state"
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Visit beautiful Beijing Tokyo Florida Alaska[root@relay3.mobvista.com:101.251.254.6 shell]#cat states
Beijing
Tokyo
Florida
Alaska
Los Angeles
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Visit beautiful Beijing
Visit beautiful Tokyo
Visit beautiful Florida
Visit beautiful Alaska
Visit beautiful Los Angeles     //不会在空格处分割

示例: 循环输出1~10,步长为3

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
for NUM in `seq 1 3 10`       \\seq设置1~10,步长为3,不写时默认为1
doecho $NUM
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
1
4
7
10[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
for ((NUM=1;NUM<=10;NUM+=3))     //C语言风格的for语句,作用相同
doecho $NUM
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
1
4
7
10

7、while语句

while test command
do
other commands
done

只要test command测试条件成立,定义的测试命令返回的是退出状态码0,while命令就会不停地循环执行定义好的命令。while中的测试和我们前面在if-then中说到的格式相同,不再赘述。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
var=5
while [ $var -gt 0 ]
doecho $varvar=$[$var - 1]
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
5
4
3
2
1

8、until语句
until命令和while命令工作的方式完全相反。until命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。

until test commands
do
other commands
done
[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
var=5
until [ $var -eq 0 ]
doecho $varvar=$[$var - 1]
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
5
4
3
2
1

当然,我们也可以将前面学到的语句嵌套使用,下面我们演示一下,值得注意的是,尽管两个循环的do和done命令没有任何差别,bash shell仍知道当第一个done命令执行时是指内部循环而非外部循环。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
var1=5
while [ $var1 -gt 0 ]
doecho "Out: $var1"for((var2=1;var2<3;var2++))dovar3=$[ $var1 * $var2 ]echo "  $var3 = $var1 * $var2"donevar1=$[$var1-1]
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Out: 55 = 5 * 110 = 5 * 2
Out: 44 = 4 * 18 = 4 * 2
Out: 33 = 3 * 16 = 3 * 2
Out: 22 = 2 * 14 = 2 * 2
Out: 11 = 1 * 12 = 1 * 2

9、循环控制
(1)break
break命令是退出循环的一个简单方法。可以用break命令来退出任意类型的循环。
示例1: 跳出单个循环

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
for ((num=1;num<10;num++))
doif [ $num -eq 5 ]thenbreakfiecho "Number is $num"
doneecho "The loop is completed"
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Number is 1
Number is 2
Number is 3
Number is 4
The loop is completed

示例2: 跳出内部循环

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
for ((a=1;a<3;a++))
doecho "Out loop: $a"for((b=1;b<10;b++))doif [ $b -eq 5 ]thenbreakfiecho "  Int loop: $b"done
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Out loop: 1Int loop: 1Int loop: 2Int loop: 3Int loop: 4
Out loop: 2Int loop: 1Int loop: 2Int loop: 3Int loop: 4

示例3: 跳出外部循环
break命令接受单个命令行参数值:break n
其中n指定了要跳出的循环层级。默认情况下,n为1,表明跳出的是当前的循环。

[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Out loop: 1Int loop: 1Int loop: 2Int loop: 3Int loop: 4
[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
for ((a=1;a<3;a++))
doecho "Out loop: $a"for((b=1;b<10;b++))doif [ $b -eq 5 ]thenbreak 2fiecho "  Int loop: $b"done
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Out loop: 1Int loop: 1Int loop: 2Int loop: 3Int loop: 4

当shell执行了break命令后,外部循环就停止了。

(2)continue
continue命令可以提前中止某次循环中的命令,但与break不同的是,它并不会完全终止整个循环。

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
for ((a=1;a<3;a++))
doecho "Out loop: $a"for((b=1;b<10;b++))doif [ $b -eq 5 ]thencontinuefiecho "  Int loop: $b"done
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh
Out loop: 1Int loop: 1Int loop: 2Int loop: 3Int loop: 4Int loop: 6Int loop: 7Int loop: 8Int loop: 9
Out loop: 2Int loop: 1Int loop: 2Int loop: 3Int loop: 4Int loop: 6Int loop: 7Int loop: 8Int loop: 9

通过上面例子的输出我们可以看到,当if中的条件满足(即b=5),shell执行continue命令,跳出本次循环,不再执行本次循环中后面剩下的命令,但整个循环会继续。

同样,continue命令也接受单个命令行参数值:continue n
和break n相同,n指定了要跳出的循环层级。默认为1,跳出当前循环。

需要特别注意的是在while和until中使用continue,我们看个例子:

[root@relay3.mobvista.com:101.251.254.6 shell]#cat test.sh
#!/bin/bash
var1=0
while   echo "Out number: $var1"[ $var1 -lt 10 ]
doif [ $var1 -gt 5 ] && [ $var1 -lt 7 ]thencontinuefiecho "  Int number: $var1"var1=$[ $var1 +1 ]
done
[root@relay3.mobvista.com:101.251.254.6 shell]#sh test.sh | more
Out number: 0Int number: 0
Out number: 1Int number: 1
Out number: 2Int number: 2
Out number: 3Int number: 3
Out number: 4Int number: 4
Out number: 5Int number: 5
Out number: 6
Out number: 6
Out number: 6
Out number: 6
Out number: 6
Out number: 6
... ...

在if-then的条件成立之前,一切正常,但当var1=6时,满足if-then条件,然后shell执行了continue命令。当shell执行continue命令时,它会跳过while循环中余下的命令。但是被跳过的部分正是$var1计数变量增值的地方,而这个变量又被用于while测试命令中。这个变量的值不会再变化了,从而产生了错误。

shell脚本中的结构化命令(if-then-else、case、for、while、until) 脚本中的循环控制相关推荐

  1. 《Linux命令行与shell脚本编程大全》第十二章 使用结构化命令

    许多程序要就对shell脚本中的命令施加一些逻辑控制流程. 结构化命令允许你改变程序执行的顺序.不一定是依次进行的 12.1 使用if-then语句 如下格式: if command then     ...

  2. Shell脚本编程基础 三 使用结构化命令

    结构化命令允许我们改变程序执行的顺序,在某些条件下执行一些命令而在其他条件下跳过另一些命令. (1)使用if-then语句 结构化命令中,最基本的类型就是if-then语句,其格式如下: if com ...

  3. Linux shell 脚本结构化命令 if-then

    shell 脚本结构化命令 1. if-then 语句基本使用 if-then 语句的基本格式: if command thencommands elifcommands elsecommands f ...

  4. Linux shell 学习笔记(8)— 使用结构化命令(if-then 语句、数值比较、字符串比较、文件比较、case 语句)

    1. 使用 if-then 语句 最基本的结构化命令就是if-then语句.if-then语句有如下格式. if command then ​ commands fi 或者 if command; t ...

  5. shell基础04 结构化命令

    几乎和别的编程语言思想一样,只是关键字写法稍有不同.总结主要包括如下几种:if-then,for,while 1. if-then 格式: if command    #根据command的状态码是否 ...

  6. 使shell用结构化命令

    shell--使用结构化命令 使用结构化命令 知识内容: # 改变命令流 # 使用if-then逻辑 # 嵌套if-then # 测试条件 # 高级if-then功能 许多程序在脚本命令之间需要某些逻 ...

  7. shell编程(七) : [shell基础] 使用结构化命令

    接上一篇文章Linux shell编程(六): 基本shell脚本 3.2 使用结构化命令 前面介绍的都是顺序执行的命令,有时需要按照逻辑顺序执行命令,这是就需要对命令命令施加一些逻辑流程控制,这样的 ...

  8. linux SHELL之结构化命令

    SHELL之使用结构化命令 使用if-then语句 Bash代码   if command then commands fi 如果if后面的命令退出状态码=0,那么就执行then 另外一种形式 Bas ...

  9. 学习笔记:CentOS7学习之二十二: 结构化命令case和for、while循环

    目录 学习笔记:CentOS7学习之二十二: 结构化命令case和for.while循环 22.1 流程控制语句:case 22.2 循环语句 22.1.2 for-do-done 22.3 whil ...

最新文章

  1. ACM图灵奖获得者:想从大数据中获益,先解决集成问题!
  2. Cisco路由器的Flash和NVRAM
  3. ATL offsetofclass 的工作原理
  4. 让机器有温度:带你了解文本情感分析的两种模型
  5. 使用Pytorch的LSTM文本分类
  6. ubuntu启动时的初始化信息二
  7. office picture manger图片处理工具下载与安装教程
  8. 实验三+161+张丽霞
  9. python周末_python区分节假日、工作日、周末
  10. apache2.2配置https协议(key文件、crt文件、csr文件生成方法)
  11. 抖音如何找到博主视频推广?筛选博主要看那些数据
  12. 【解惑】女生适合干计算机什么方面的工作
  13. react笔记_07组件实例化对象的三大属性
  14. 占豪--2010年的市场机会在哪里(兼谈股指期货与楼市)
  15. CAD制图初学入门技巧:如何批量生成CAD填充边界?
  16. Android.bp入门教程
  17. MSP430如何使用energia(TI公司的arduino简易编译器)
  18. 对某网站被挂黑广告源头分析
  19. python中的middle_Python wx.EVT_MIDDLE_DCLICK属性代码示例
  20. Linux服务篇-sshd服务

热门文章

  1. 【MySQL】MySQL内连接和外连接详细总结
  2. html video 视频.html
  3. 美图秀秀自建贴纸手机存储
  4. 网站设计中常犯的错误
  5. 西北工业大学JAVA语言试题_2020年西北工业大学英语语言文学考研真题试卷及试题答案,英语综合知识测试考研试题下载...
  6. 微信jssdk开发java版_微信jssdk
  7. 我的新书《Visual C#.NET原理与实务》出版了
  8. 逍遥自在学C语言 | 指针陷阱-空指针与野指针
  9. 晟元协议指纹头,单片机开发踩坑指南
  10. Beaglebone 中 U-Boot 的启动过程