700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > shell脚本中的结构化命令(if-then-else case for while until) 脚本中的循环控制

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

时间:2022-05-19 17:33:03

相关推荐

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

1、 结构化命令

上一次我们学习了shell脚本的一些基础知识,包括环境变量、重定向、数学运算、退出脚本的方式等,想了解的可以戳这个: shell脚本基础

之前,在我们的示例shell脚本里,shell按照命令在脚本中出现的顺序依次进行处理。然而有时候,我们需要对shell脚本中的命令施加一些逻辑流程控制。有一类命令会根据条件使脚本跳过某些命令。这样的命令通常称为结构化命令,它允许我们改变程序执行的顺序。下面,我们学习一下常见的结构化命令 :

2、if-then语句

一般格式如下 :

if commandthen commandsfi

bash shell的if语句会运行if后面的那个命令。如果该命令的退出状态码是0即该命令成功运行,位于then部分的命令就会被执行。如果该命令的退出状态码是其他值,then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。fi语句用来表示if-then语句到此结束。

示例 : 判断用户名当前是否在系统上使用,如果有用户使用了那个登录名,脚本会显示一些文本信息并列出该用户HOME目录的bash文件。

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bash# testing if-thenusername=Miyaif grep $username /etc/passwdthenecho "$username exits!"ls -a /home/$username/.b*fi[root@:101.251.254.6 shell]#sh test.shMiya:x:1026:1026::/home/Miya:/bin/bashMiya exits!/home/Miya/.bash_logout /home/Miya/.bash_profile /home/Miya/.bashrc

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

3、if-then-else语句

if commandthen commandselse commandsfi

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bash# testing if-thenusername=$1if grep $username /etc/passwdthenecho "$username exits!"ls -a /home/$username/.b*elseecho "$username is not exits !"fi[root@:101.251.254.6 shell]#sh test.sh MiyaMiya:x:1026:1026::/home/Miya:/bin/bashMiya exits!/home/Miya/.bash_logout /home/Miya/.bash_profile /home/Miya/.bashrc[root@:101.251.254.6 shell]#sh test.sh hahahaha is not exits !

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

if command1then commandselif command2then more commandsfi

elif语句行提供了另一个要测试的命令,这类似于原始的if语句行。如果elif后命令的退出状态码是0,则bash会执行第二个then语句部分的命令。

示例 : 判断存在某个用户名以及该用户的目录是否存在。

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

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

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

4、if条件测试

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

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

注意,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错。

可以判断三类条件:数值、字符串、文件

(1)数值比较

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

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

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

(2)字符串比较

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashtestuser=rootif [ $USER = $testuser ]thenecho "Welcome $testuser!"fi[root@:101.251.254.6 shell]#sh test.shWelcome root!

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashstring1=asdfgstring2=hjkif [ $string1 > $string2 ]thenecho "$string1 is more than $string2!"elseecho "$string1 is less than $string2"fi[root@:101.251.254.6 shell]#sh test.shasdfg is more than hjk![root@:101.251.254.6 shell]#ll hjk-rw-r--r--. 1 root root 0 Jul 31 12:09 hjk

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashstring1=asdfgstring2=hjkif [ $string1 \> $string2 ]thenecho "$string1 is more than $string2!"elseecho "$string1 is less than $string2"fi[root@:101.251.254.6 shell]#sh test.shasdfg is less than hjk

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashstring1=Teststring2=testif [ $string1 \> $string2 ]thenecho "$string1 is more than $string2!"elseecho "$string1 is less than $string2"fi[root@:101.251.254.6 shell]#sh test.shTest is less than test

(3)文件比较

if-then语句还允许使用布尔逻辑来组合测试,逻辑与和逻辑或 :

 [ condition1 ] && [ condition2 ]

 [ condition1 ] || [ condition2 ]

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

(4)if-then的高级特性

双括号命令允许你在比较过程中使用高级数学表达式。

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

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashif [[ $USER == r* ]]thenecho "Welcome $USER!"fi[root@:101.251.254.6 shell]#sh test.shWelcome root!

5、case语句

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

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashpet=$1case $pet indog|cat)echo $pet is lovely;;pig)echo $pet is fat;;*)echo error;;esac[root@:101.251.254.6 shell]#sh test.sh dogdog is lovely[root@:101.251.254.6 shell]#sh test.sh duckerror

6、for语句

for var in list do commands done

在list参数中,你需要提供迭代中要用到的一系列值。for命令最基本的用法就是遍历for命令自身所定义的一系列值。

示例: 需要注意的有两处,系列值中包含空格的要用双引号(" "),包含单引号的需要转义或者用双引号。

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

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

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

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

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

7、while语句

while test command do other commands done

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashvar=5while [ $var -gt 0 ]doecho $varvar=$[$var - 1]done[root@:101.251.254.6 shell]#sh test.sh54321

8、until语句

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

until test commands do other commands done

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashvar=5until [ $var -eq 0 ]doecho $varvar=$[$var - 1]done[root@:101.251.254.6 shell]#sh test.sh54321

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

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

9、循环控制

(1)break

break命令是退出循环的一个简单方法。可以用break命令来退出任意类型的循环。

示例1: 跳出单个循环

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

示例2: 跳出内部循环

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

示例3: 跳出外部循环

break命令接受单个命令行参数值:break n

其中n指定了要跳出的循环层级。默认情况下,n为1,表明跳出的是当前的循环。

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

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

(2)continue

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

[root@:101.251.254.6 shell]#cat test.sh#!/bin/bashfor ((a=1;a<3;a++))doecho "Out loop: $a"for((b=1;b<10;b++))doif [ $b -eq 5 ]thencontinuefiecho " Int loop: $b"donedone[root@:101.251.254.6 shell]#sh test.shOut loop: 1Int loop: 1Int loop: 2Int loop: 3Int loop: 4Int loop: 6Int loop: 7Int loop: 8Int loop: 9Out 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@:101.251.254.6 shell]#cat test.sh#!/bin/bashvar1=0while echo "Out number: $var1"[ $var1 -lt 10 ]doif [ $var1 -gt 5 ] && [ $var1 -lt 7 ]thencontinuefiecho " Int number: $var1"var1=$[ $var1 +1 ]done[root@:101.251.254.6 shell]#sh test.sh | moreOut number: 0Int number: 0Out number: 1Int number: 1Out number: 2Int number: 2Out number: 3Int number: 3Out number: 4Int number: 4Out number: 5Int number: 5Out number: 6Out number: 6Out number: 6Out number: 6Out number: 6Out number: 6......

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。