# 循环(loop)
循环可以不断执行某个程序段楼,直到用户设定的条件达成为止。
# while do done、until do done(不定循环)
当条件成立时,执行循环体
while [ condition ] # 中括号中条件判断
do # 循环开始
程序段落
done # 循环结束
1
2
3
4
2
3
4
还有一种不定循环的方式,当条件成立时退出循环体
until [ condition ]
do
程序段落
done
1
2
3
4
2
3
4
范例:让使用者输入 yes 或则是 YES 才结束程序的执行,否则就一直告知用户输入字符串
vim yes_to_stop.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
while [ "${yn}" != 'yes' -a "${yn}" != 'YES' ]
# 使用 until 则是如下
# until [ "${yn}" == 'yes' -o "${yn}" == 'YES' ]
do
read -p '请输入 yes 或 YES 退出程序' yn
done
echo "你输入了正确答案"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
测试如下
[mrcode@study bin]$ ./yes_to_stop.sh
请输入 yes 或 YES 退出程序j
请输入 yes 或 YES 退出程序jj
请输入 yes 或 YES 退出程序yes
你输入了正确答案
1
2
3
4
5
2
3
4
5
如果想要计算 1+2+3+..100
则如下写
vim cal_1_100.sh
#!/bin/bash
# Program:
# 计算 1+2+3+..100 的结果
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
total=0 # 计算结果
i=0 # 当前数值
while [ "${i}" != 100 ]
do
i=$(($i+1)) # 每次增加 1
total=$(($total+$i))
done
echo "1+2+3+..100 = ${total}"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# for...do...done
固定循环
for var in con1 con2 con3 ...
do
循环体
done
1
2
3
4
2
3
4
范例:假设有三种动物,分别是 dog、cat、elephant 三种,输出三行信息,如 There are dogs...
之类的信息
vim show_animal.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
for animal in dog cat elephant
do
echo "There are ${animal}s..."
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
/etc/passwd 中第一个字段存放了用户名,使用循环打印出每个用户名的 id 信息;可使用 cut 截取第一字段,使用 id指令获取用户名的信息(标识符与特殊参数)
vim userid.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
users=$(cut -d ':' -f1 /etc/passwd) # 获取到所有的用户名
for user in ${users}
do
id ${user}
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
当然还可以使用数字来做循环项,比如需要执行 ping 192.168.1.1~192.168.1.100
也就是从 1 ping 到 100,但是不可能需要我们手动输入 100 个数字吧
vim pingip.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
network="192.168.0" # 先定义一个网域的前部分
for sitenu in $(seq 1 100) # seq 为 sequence 连续的意思
do
# ping -c 1 -w 1 192.168.0.101 &> /dev/null && echo "1" || echo "0"
# 不显示执行结果,并获取命令是否执行成功
ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
if [ "${result}" == 0 ]; then
echo "${network}.${sitenu} is up"
else
echo "${network}.${sitenu} is down"
fi
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
测试结果
[mrcode@study bin]$ ./pingip.sh
192.168.0.1 is up
192.168.0.2 is down
192.168.0.3 is down
..
1
2
3
4
5
2
3
4
5
对于 $(seq 1 100)
来说,还可以使用 bash 的内建机制 {1..100}
来代替,中间两个点表示连续的意思,比如想要输出 a~g 则可以使用 a..g
最后一个范例:
- 让用户输入一个目录
- 如果目录不存在,则提示并退出程序
- 如果目录存在,则获取该目录下第一级文件是否可读、可写、可执行
vim dir_perm.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "请输入一个目录,将会检测该目录是否可读、可写、可执行:" dir
# 判定输入不为空,并且目录存在
if [ "${dir}" == '' -o ! -d "${dir}" ]; then
echo "The ${dir} is NOT exist in your system"
exit 1
fi
# 获取该目录下的文件权限信息
filelist=$(ls ${dir})
for file in ${filelist}
do
perm=""
test -r "${dir}/${file}" && perm="${perm} readable"
test -w "${dir}/${file}" && perm="${perm} writable"
test -x "${dir}/${file}" && perm="${perm} executable"
echo "The file ${dir}/${file}'s permission is ${perm}"
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
使用这种方式,可以很轻易的来处理一些文件的特性
# for...do...done
数值处理
for (( 初始值; 限制值; 执行步阶))
do
循环体
done
1
2
3
4
2
3
4
- 初始值:某个变量在循环中的起始值,可以以 i=1 设置好初始值
- 限制值:当变量值在这个限制值范围内,则继续循环。例如 i<=100
- 执行步阶:每执行一次循环时,变量的变化量。例如 i=i+1,如果是自增则可以使用 i++ 来替代
范例:计算从 1 累加到指定数值的结果
vim cal_1_100-2.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "请输入一个数值,将计算出从 1 累加到该数值的计算结果" nu
total=0
for (( i=1; i<=${nu}; i++))
do
total=$((${total}+${i}))
done
echo "1+..+${nu} = ${total}"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
测试输出如下
[mrcode@study bin]$ ./cal_1_100-2.sh
请输入一个数值,将计算出从 1 累加到该数值的计算结果2
1+..+2 = 3
[mrcode@study bin]$ ./cal_1_100-2.sh
请输入一个数值,将计算出从 1 累加到该数值的计算结果100
1+..+100 = 5050
1
2
3
4
5
6
2
3
4
5
6
# 搭配随机数与数组的实验
现在大概已经能够掌握 shell script 了。
现在来做个有趣的小东西,今天中午吃啥?要完成这个脚本,首先需要将全部的店家输入到一组数组中,再通过随机数的处理,获得可能的值
vim what_to_eat.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# 定义你搜集到的店家信息
eat[1]="卖当当汉堡"
eat[2]="肯爷爷炸鸡"
eat[3]="彩虹日式便当"
eat[4]="越油越好吃打呀"
eat[5]="想不出吃什么"
eat[6]="太师傅便当"
eat[7]="池上便当"
eat[8]="怀恋火车便当"
eat[9]="一起吃泡面"
eat[10]="太上皇"
eatnum=10 # 一共有几家可用的店铺
check=$((${RANDOM} * ${eatnum} / 32767 + 1))
echo "your may eat ${eat[${check}]}"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
测试输出
[mrcode@study bin]$ ./what_to_eat.sh
your may eat 太上皇
[mrcode@study bin]$ ./what_to_eat.sh
your may eat 越油越好吃打呀
[mrcode@study bin]$ ./what_to_eat.sh
your may eat 想不出吃什么
[mrcode@study bin]$ ./what_to_eat.sh
1
2
3
4
5
6
7
2
3
4
5
6
7
继续深入,一次性输出 3 个选择,并且不能重复
vim what_to_eat-2.sh
#!/bin/bash
# Program:
#
# History:
# 2020/02/12 mrcode first relese
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# 定义你搜集到的店家信息
eat[1]="卖当当汉堡"
eat[2]="肯爷爷炸鸡"
eat[3]="彩虹日式便当"
eat[4]="越油越好吃打呀"
eat[5]="想不出吃什么"
eat[6]="太师傅便当"
eat[7]="池上便当"
eat[8]="怀恋火车便当"
eat[9]="一起吃泡面"
eat[10]="太上皇"
eatnum=10 # 一共有几家可用的店铺
# 其实就是需要轮询出来 3 个不同的索引结果
eated=0 # 已选中数量
while [ "${eated}" -lt 3 ];
do
check=$((${RANDOM} * ${eatnum} / 32767 + 1))
mycheck=0 # 当为 0 时,表示不重复
# 去重检查
if [ ${eated} -gt 0 ]; then # 当已选中至少一个店铺的时候,才执行
for i in $(seq 1 ${eated})
do
if [ "${eatedcon[$i]}" == $check ]; then
mycheck=1
fi
done
fi
if [ ${mycheck} == 0 ]; then
echo "your may eat ${eat[${check}]}"
eated=$(( ${eated} + 1 ))
eatedcon[${eated}]=${check} # 将已选中结果存储起来
fi
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46