0%

结构控制

结构控制

Bash中结构控制关键字有:if for while util cast select

if

1
2
3
4
5
6
[root@vm-101 ~]# if [ 111 -eq 111 ]; then					# 如果111 -eq 111(-eq等于)
> echo 'yes' # 上面的表达式返回真时,打印yes
> else # 否则的意思
> echo 'no' # 上面的表达式返回假时,打印no
> fi # 一定要记得这个结束符
yes # 111 -eq 111,返回真,所以打印yes

上面只有一个判断条件,如果有多个判断条件呢?

1
2
3
4
5
6
7
8
[root@vm-101 ~]# if [ 111 -eq 112 ]; then					# 第一个条件测试
> echo '111 -eq 112'
> elif [ 222 -eq 222 ]; then # 如果第一条件测试没匹配上,就继续判断第二个条件测试
> echo '222 -eq 222'
> else # 前面所有的条件测试都没匹配上就执行下面的语句
> echo '都不对'
> fi
222 -eq 222 # 第二个条件测试匹配上了

注意:

[是一个命令, ]也是一个命令,是关键字,它们是配对的。

命令前后应该有什么?应该有空格或者;&这类符号。不然bash就会找不到这个命令。

类似的还有[[ ]]

切记切记,初学者常犯的错误(比如曾今的我)。

for

循环控制

1
2
3
4
5
6
7
8
[root@vm-101 ~]# for i in 1 2 3 4							# 循环打印1 2 3 4
> do
> echo $i
> done
1
2
3
4
1
2
3
4
5
6
7
8
9
[root@vm-101 ~]# list=(11 22 33 44)
[root@vm-101 ~]# for i in ${list[@]} # 循环遍历数组list
> do
> echo $i
> done
11
22
33
44
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@vm-101 ~]# for (( i=0; i<=10; i++ ))		# 遍历一个数学表达式
> do
> echo $i
> done
0
1
2
3
4
5
6
7
8
9
10

这种语法类似C语言中的for循环。

i=0,定义$i的初始值为0

i<=10,定义$i<=10时,不退出for循环。只要不满足这个条件,for循环就结束。

i++,for循环没执行一次,都需要执行下这个操作。可以理解成步进。

写for循环的时候要非常小心,非常容易造成死循环。下面演示几种:

1
[root@vm-101 ~]# for (( i=0; ; i++ )); do echo $i; done

这种情况没有指定for循环的退出条件,就没办法退出for循环,会一直跑下去,知道天荒地老,海枯石烂。

1
[root@vm-101 ~]# for (( i=0; i<=10; )); do echo $i; done

这种情况有退出条件,但是这个条件永远也不会满足。因为没有指定步进。

要避免这种情况怎么办?

break

1
2
3
4
5
6
7
8
9
10
11
12
[root@vm-101 ~]# for  (( i=0; ; i++ )); do
> if [ $i -gt 5 ]; then
> break # 如果$i大于5,就break。退出for循环
> fi
> echo $i
> done
0
1
2
3
4
5

continue

1
2
3
4
5
6
7
8
9
10
11
[root@vm-101 ~]# for  (( i=0; i<=5; i++ )); do
> if [ $i -eq 3 ]; then
> continue # 当$i等于3的时候,这次循环就不往下执行了,跳过,继续执行下一次
> fi
> echo $i
> done
0
1
2
4
5

while

类似for循环,可以根据自己喜好和实际环境替换。

1
2
3
4
5
6
7
8
9
10
11
12
[root@vm-101 ~]# i=5
[root@vm-101 ~]# while (( $i >= 0 )) # 只要while后面的表达式返回真,就一直运行
> do
> echo $i
> let "i--" # 执行 i-- 自减运算
> done
5
4
3
2
1
0 # $i=0, 在下一次while循环中,$i=-1,不大于等于0,返回假,所以退出循环

用while遍历文件

1
2
3
4
5
6
[root@vm-101 ~]# cat /etc/hosts | while read line
> do
> echo $line
> done
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

这里用到了前面学的管道。

又遇到了一个新的命令read。暂时不用细究这个read是干嘛的。先把read line简单理解成读取文件中的一行。

这里有两行,就是循环了两次。

验证下:

1
2
3
4
5
[root@vm-101 ~]# cat /etc/hosts | while read line; do echo $line; echo ------------- ; done
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
-------------
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
-------------

在每次循环中都打印了一串————-。这里出现了两次,所以就是循环了两次。

在while循环中同样可以使用breakcontinue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@vm-101 ~]# i=10
[root@vm-101 ~]# while (( $i >= 0 ))
> do
> let "i--"
> if [ $i -eq 8 ]; then
> continue
> fi
>
> if [ $i -le 3 ]; then
> break
> fi
> echo $i
> done
9
7
6
5
4

while循环同样要注意避免死循环

until

与while相反。直至条件为真时退出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@vm-101 ~]# a=0
[root@vm-101 ~]# until [ ! $a -lt 10 ] # !取反的意思
> do
> echo $a
> a=`expr $a + 1` # 数学计算并把结果赋值给变量a
> done
0
1
2
3
4
5
6
7
8
9

case

if ... elif ... elif ... elif ... else ... fi更优雅的一种写法。

其实也优雅不到哪里去。个人感觉和一堆if else没有太大的区别。但是还是要学习学习的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@vm-101 ~]# a=1
[root@vm-101 ~]# case $a in # 固定写法
> 1)
> echo "111"
> ;; # 一个判断的结束,两个;,别弄错了
> 2)
> echo "222"
> ;;
> *) # 如果前面都没有匹配上,就执行这个默认的
> echo "*"
> ;;
> esac # 结束字符,别忘记了
1

[root@vm-101 ~]# a=2
[root@vm-101 ~]# case $a in 1) echo "111"; ;; 2) echo "222"; ;; *) echo "***"; ;; esac
2

[root@vm-101 ~]# a=3
[root@vm-101 ~]# case $a in 1) echo "111"; ;; 2) echo "222"; ;; *) echo "***"; ;; esac
***

select

有点类似for循环。不过它是一个交互式的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@vm-101 ~]# list=(11 22 33 44)
[root@vm-101 ~]# select i in ${list[@]}
> do
> echo $i
> done
1) 11
2) 22
3) 33
4) 44
#? 1 # 输入1
11
#? 2 # 输入2
22
#? 3
33
#? 4
44
#? 5

#? ^C # Ctrl-C结束
1
2
3
4
5
6
7
[root@vm-101 ~]# select i in ${list[@]}; do echo $i; break; done
1) 11
2) 22
3) 33
4) 44
#? 1
11

也可以结合break来退出select。