0%

函数

函数

到这里,大家已经会写一个10行,20行的,甚至100行的bash脚本了。

但是更长的脚本,可能就不太方便写了。过程太长,写了后面的忘了前面的。不能再记流水账。

这时候,我们需要来认识下函数。

定义函数的语法

1
2
3
[function] function-name() {
commands
}

关键字function可选。我比较懒,一般都不写。

function-name的命名规则和变量的命名规则一样。

commands是一堆要用到的command,或者其他function。

函数带来的好处:

  1. 在长的脚本中,代码结构可以更加有逻辑,条理清晰。

  2. 一个函数就是一个小的功能,维护起来也会方便一些。

第一个小函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@vm-101 ~]# cat func1.sh
#!/bin/bash

# 第一个小函数

func1(){ # 定义func1函数
echo "这是第一个小函数"
echo "这里只是演示,没有啥实际作用"
}

func1 # 调用func1函数

exit 0


[root@vm-101 ~]# bash func1.sh
这是第一个小函数
这里只是演示,没有啥实际作用

我们来改造前面的脚本

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
47
48
49
50
51
52
53
54
55
56
57
[root@vm-101 ~]# cat yanghuisanjiao.sh
#!/bin/bash

# 注释说明,好习惯

echo_blank(){
for ((a=$[ $size - $i ]; a>0; a--)) # 打印前面的空格
do
echo -n " "
done

return 0
}

echo_num(){
for ((b=1; b<${#list[@]}; b++)) # 打印后面的数字
do
var=$[ ${list[$[b-1]]} + ${list[b]} ]
echo -n " $var"
list_tmp=(${list_tmp[@]} $var)
done
list=(${list_tmp[@]} 0) # 这一行计算结束了,把这行的结果存到list。供下次循环使用。
echo
}

read -p "输入杨辉三角的大小:" size

list=(0 1) # 临时存放上一行的状态,第一行没有上一行。给一个初始状态。

for ((i=1; i<=$size; i++))
do
echo_blank
list_tmp=(0) # 记录当前行的计算过程。每次新的循环要清空。
echo_num
done

exit 0

[root@vm-101 ~]# bash yanghuisanjiao.sh
输入杨辉三角的大小:5
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
[root@vm-101 ~]# bash yanghuisanjiao.sh
输入杨辉三角的大小:10
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1

把等腰三角形和杨辉三角合拼,放在一起变成一个大脚本

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
[root@vm-101 ~]# cat dengyaosanjiao.sh
#!/bin/bash

# 注释说明,好习惯

echo_dengyao(){
for ((i=1; i<=$size; i++))
do
for ((a=$[ $size - $i ]; a>0; a--))
do
echo -n " "
done

for ((b=$[ 2 * $i - 1 ]; b>0; b--))
do
echo -n "#"
done
echo
done

return 0
}

echo_blank(){
for ((a=$[ $size - $i ]; a>0; a--)) # 打印前面的空格
do
echo -n " "
done

return 0
}

echo_num(){
for ((b=1; b<${#list[@]}; b++)) # 打印后面的数字
do
var=$[ ${list[$[b-1]]} + ${list[b]} ]
echo -n " $var"
list_tmp=(${list_tmp[@]} $var)
done
list=(${list_tmp[@]} 0) # 这一行计算结束了,把这行的结果存到list。供下次循环使用。
echo
}

echo_yanghuisanjiao(){
list=(0 1) # 临时存放上一行的状态,第一行没有上一行。给一个初始状态。

for ((i=1; i<=$size; i++))
do
echo_blank # 函数中调用另外一个函数
list_tmp=(0) # 记录当前行的计算过程。每次新的循环要清空。
echo_num # 函数中调用另外一个函数
done

return 0
}

read -p "输入三角形的大小:" size

echo_dengyao # 打印等腰三角形
echo_yanghuisanjiao # 打印杨辉三角

exit 0



[root@vm-101 ~]# bash dengyaosanjiao.sh
输入三角形的大小:5
#
###
#####
#######
#########
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1

这样一个脚本的结构就比较清楚。再长一些也没有关系。

每个函数控制在一个屏幕以内,一眼就能从头看到尾。这样比较好。

如果再长,几千行,几万行。就不适合放在一个脚本中了。可以拆分成多个脚本。

这里只是提示用.source命令来引用另外一个脚本。

对,没错。前面讲环境配置的时候提到了。

但这不是重点。如果真有这么多代码要维护。可能需要考虑用更加高级的语言来完成这些功能。比如:python,go,php,perl等。

函数的参数

函数可以理解成自己定义的一个一个小命令,小工具。只不过是定义在一个脚本里面。

命令可以有很多很多的参数,那么函数也应该有。的确它也可以有。

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
[root@vm-101 ~]# cat ping.sh
#!/bin/bash

# 注释说明,好习惯

test_ping(){
ping -c 3 $1 # `$1`,函数的位置参数。注意:这里不是脚本的位置参数,不要弄混了。

return 0
}

url="www.baidu.com"

test_ping $url # 注意这里,和之前的不一样了。后面多了一个参数。

exit 0


[root@vm-101 ~]# bash ping.sh
PING www.a.shifen.com (39.156.66.18) 56(84) bytes of data.
64 bytes from 39.156.66.18 (39.156.66.18): icmp_seq=1 ttl=63 time=6.45 ms
64 bytes from 39.156.66.18 (39.156.66.18): icmp_seq=2 ttl=63 time=6.62 ms
64 bytes from 39.156.66.18 (39.156.66.18): icmp_seq=3 ttl=63 time=6.74 ms

--- www.a.shifen.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2010ms
rtt min/avg/max/mdev = 6.455/6.607/6.743/0.118 ms

一个很简单的函数。

函数的返回值

其实在上面的函数中,我都有些一个return 0。这就是给了函数一个返回值。

用来给后面的代码判断这个函数是不是正常执行了。这也是一个好习惯。

注意: 这里不能用exit,否则就直接退出整个脚本。

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
[root@vm-101 ~]# cat func2.sh
#!/bin/bash

# 注释说明,好习惯

func1(){
echo "11111"

return 0
}

func2(){
echo "22222"

return 2 # 返回一个非零,在bash中,就是有错误。
}

func1 && echo "func1 OK" || echo "func1 Error" # 复习下 && 和 || 操作符
func2 && echo "func2 OK" || echo "func2 Error"

exit 0


[root@vm-101 ~]# bash func2.sh
11111
func1 OK
22222
func2 Error