shell之数组和函数
1、数组
数组分为三类,分别是变量,普通变量和关联数组。
①变量。
1
2
3
4
5
6name=alice
---------------------
|a |l |i |c |e |
---------------------
|0 |1 |2 |3 |4 | #索引
---------------------
②普通数组,下标是整数。
1
2
3
4
5
6books=(linux shell awk openstack docker)
---------------------------------------------
|linux |shell |awk |openstack |docker |
---------------------------------------------
|0 |1 |2 |3 |4 | #索引
---------------------------------------------eg:
1
2
3[root@centos7 shell]# books=(linux shell awk openstack docker)
[root@centos7 shell]# echo ${books[3]}
openstack
关联数组,下标是字符串。
1
2
3
4
5
6info=([name]=zhu [sex]=male [age]=22 [height]=170 [skill]=play)
-----------------------------------------
|zhu |male |22 |170 |play |
-----------------------------------------
|name |sex |age |height |skill | #索引
-----------------------------------------eg:
1
2
3
4
5
6
7
8
9
10
11
12
13declare -a表示普通数组,直接在终端输入,可以查看所有的普通数组
declare -A表示关联数组,直接在终端输入,可以查看所有的关联数组
declare -i表示整数
[root@centos7 shell]# declare -A info # 先要声明关联数组
[root@centos7 shell]# info=([name]=zhu [sex]=male [age]=22 [height]=170 [skill]=play)
[root@centos7 shell]# echo ${info[name]}
zhu
[root@centos7 shell]# info+=([college]=gzmtu) # 往数组里增加一个元素
[root@centos7 shell]# echo ${info[@]} # 查看数组所有元素
zhu 170 22 play gzmtu male
[root@centos7 shell]# let info[age]++ # 使某一个下标的值加1
[root@centos7 shell]# echo ${info[age]}
23
操作数组:
①定义数组:
1
2
3
4
5
6
7
8方法1:一次赋一个值,即数组名[下标]=变量值
array[0]=peer
array[1]=apple
方法2:一次赋多个值
array=(abc def ghi)
array=(`cat /ec/passwd`)# 将该文件中的每一个行作为一个元素赋值给数组array
array=(1 2 3 4 5 "shell" [20]=wangji) # 可以给第20个元素赋值②查看数组。
1
2declare -a
declare -A③访问数组元素。
1
2
3
4
5
6echo ${array[0]} # 访问数组中的第一个元素
echo ${array[@]} # 访问数组中的所有元素,等同于echo ${array[*]}
echo ${#array[@]} # 统计数组元素的个数
echo ${!array2[@]} # 获取数组元素的下标
echo ${array[@]:1} # 从数组下标1开始,针对非关联数组
echo ${array[@]:1:2} # 从数组下标1开始,访问2个元素,针对非关联数组eg:
1
2
3
4
5
6
7
8
9
10
11
12
13[root@centos7 shell]# array=(linux shell awk openstack docker)
[root@centos7 shell]# echo ${array[0]}
linux
[root@centos7 shell]# echo ${array[@]}
linux shell awk openstack docker
[root@centos7 shell]# echo ${#array[@]}
5
[root@centos7 shell]# echo ${!array[@]}
0 1 2 3 4
[root@centos7 shell]# echo ${array[@]:1}
shell awk openstack docker
[root@centos7 shell]# echo ${array[@]:1:2}
shell awk
④遍历数组:通过数组元素的下标进行遍历。
eg1:while遍历/etc/hosts文件的所有行并输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17[root@centos7 shell]# cat cathost.sh
!/usr/bin/bash
while read line
do
hosts[++i]=$line
done </etc/hosts
echo "hosts first: ${hosts[1]}"
获得数组的下标
for i in ${!hosts[@]}
do
echo "$i: ${hosts[i]}"
done
[root@centos7 shell]# bash cathost.sh
hosts first: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
1: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2: ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6eg2:for遍历/etc/hosts文件的所有行并输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23[root@centos7 shell]# cat cathost.sh
!/usr/bin/bash
for见到空格,tab,换行都会分割
OLD_IFS=$IFS
若在最前面加上IFS=$'\n'就和eg1的结果一样了
IFS=$'\n'
for line in `cat /etc/hosts`
do
hosts[++j]=$line
done
echo "hosts first: ${hosts[1]}"
获得数组的下标
for i in ${!hosts[@]}
do
echo "$i: ${hosts[i]}"
done
还原分隔符
IFS=$OLD_IFS
[root@centos7 shell]# bash cathost.sh
hosts first: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
1: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2: ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6eg3:使用Array实现性别统计。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24[root@centos7 shell]# awk '{print $2}' sex.txt |sort |uniq -c # 使用awk统计也行
2 f
1 m
[root@centos7 shell]# cat sex.txt
bob m
alice f
rose f
[root@centos7 shell]# cat countsex.sh
!/usr/bin/bash
declare -A sex
while read line
do
type=`echo $line |awk '{print $2}'`
# 把要统计的对象作为数组的下标
let sex[$type]++
done < sex.txt
for i in ${!sex[@]}
do
echo "$i: ${sex[$i]}" # 关联数组的下标要加$
done
[root@centos7 shell]# bash countsex.sh
f: 2
m: 1eg4:统计不同类型shell的数量。
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[root@centos7 shell]# awk -F ":" '{print $NF}' /etc/passwd |sort |uniq -c # 使用awk统计也行
8 /bin/bash
1 /bin/sync
1 /sbin/halt
39 /sbin/nologin
1 /sbin/shutdown
[root@centos7 shell]# cat countpasswd.sh
!/usr/bin/bash
declare -A shells
while read line
do
# -F指使用':'分割,因为passwd每行的数据都是':'分割的,$NF表示最后一列
type=`echo $line |awk -F ":" '{print $NF}'`
let shells[$type]++
done </etc/passwd
for i in ${!shells[@]}
do
echo "$i: ${shells[$i]}"
done
[root@centos7 shell]# bash countpasswd.sh
/sbin/nologin: 39
/bin/sync: 1
/bin/bash: 8
/sbin/shutdown: 1
/sbin/halt: 1eg5:Array统计TCP连接状态数量。
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!/usr/bin/bash
declare -A shells
type=`ss -an |grep ":80" |awk '{print $2}'`
for i in $type
do
let shells[$i]++
done
for i in ${!shells[@]}
do
echo "$i: ${shells[$i]}"
done
每隔2s一直执行该脚本
执行命令:watch -n2 tcp.sh
第二种方式:使用死循环,最好在最后加个sleep 1;clear
!/usr/bin/bash
while :
do
unset shells
declare -A shells
type=`ss -an |grep ":80" |awk '{print $2}'`
for i in $type
do
let shells[$i]++
done
for i in ${!shells[@]}
do
echo "$i: ${shells[$i]}"
done
sleep 1;clear
done
2、函数
函数作用。
- 完成特定功能的代码片段(块)。
- 在shell中定义函数可使得代码模块化,便于复用代码。
定义函数。
方法一:
1
2
3
4函数名()
{
函数要实现的功能代码
}方法二:
1
2
3
4function 函数名
{
函数要实现的功能代码
}eg1:写一个阶乘函数并调用,写死阶乘数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@centos7 shell]# cat test.sh
!/usr/bin/bash
factorial()
{
factorial=1
for((i=1;i<=10;i++))
do
factorial=$[$factorial * $i]
done
echo "10的阶乘:$factorial"
}
factorial
[root@centos7 shell]# bash test.sh
10的阶乘:3628800eg2:写一个阶乘函数并调用,阶乘数通过变量绑定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[root@centos7 shell]# cat test.sh
!/usr/bin/bash
factorial()
{
factorial=1
for((i=1;i<=$num;i++))
do
factorial=$[$factorial * $i]
done
echo "$num的阶乘:$factorial"
}
调用函数之前,定义了一个num变量
num=5
factorial
[root@centos7 shell]# bash test.sh
5的阶乘:120eg3:写一个阶乘函数并调用,阶乘数通过调用此函数时传入。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15[root@centos7 shell]# cat test.sh
!/usr/bin/bash
factorial()
{
factorial=1
for((i=1;i<=$1;i++))
do
factorial=$[$factorial * $i]
done
echo "10的阶乘:$factorial"
}
这个10会直接传递给函数factorial()的$1,直接执行./factorial.sh
factorial 10
[root@centos7 shell]# bash test.sh
10的阶乘:3628800eg4:写一个阶乘函数并调用,阶乘数通过调用此脚本时传入。
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[root@centos7 shell]# cat test.sh
!/usr/bin/bash
factorial()
{
factorial=1
for((i=1;i<=$1;i++))
do
factorial=$[$factorial * $i]
done
echo "10的阶乘:$factorial"
}
这个$1会直接传递给函数factorial()的$1,直接执行./factorial.sh 10
factorial $1
[root@centos7 shell]# bash test.sh 10
10的阶乘:3628800
注意区分
[root@centos7 shell]# cat test.sh
!/usr/bin/bash
factorial()
{
factorial=1
for((i=1;i<=$1;i++))
do
factorial=$[$factorial * $i]
done
echo "$1的阶乘:$factorial"
}
这个$1会直接传递给函数factorial()的$1,直接执行./factorial.sh 5 8 10
作为函数来讲,$1,$2,$3都是函数的第一个参数
factorial $1
factorial $2
factorial $3
[root@centos7 shell]# bash test.sh 5 8 10
5的阶乘:120
8的阶乘:40320
10的阶乘:3628800
函数的返回值。
函数的返回值:函数最后一条命令的执行结果,要么0,要么非0,但是可利用return自定义返回结果,但是不能超过255。
程序的返回值:程序最后一条命令的执行结果。
return只能返回0-255的数。
eg1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[root@centos7 shell]# cat testreturn.sh
!/usr/bin/bash
fun2()
{
read -p "enter num:" num
return $[2*$num]
}
fun2
shell的返回码最高是255,如果超过255就会报错
echo "fun2 return value: $?"
[root@centos7 shell]# bash testreturn.sh
enter num:10
fun2 return value: 20 # 正确答案
[root@centos7 shell]# bash testreturn.sh
enter num:200
fun2 return value: 144 # 错误答案eg2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@centos7 shell]# cat testreturn.sh
!/usr/bin/bash
fun2()
{
read -p "enter num:" num
# 自定义函数的返回值,叫做函数的输出,可以是字符串
echo $[2*$num]
}
将函数的调用结果赋值给变量result
result=`fun2`
echo "fun2 return value: $result"
[root@centos7 shell]# bash testreturn.sh
enter num:200
fun2 return value: 400 # 正确答案eg3:函数返回-输出数组变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22[root@centos7 shell]# cat testarray.sh
!/usr/bin/bash
!/usr/bin/bash
num=(1 2 3)
array()
{
echo "all parameters: $*"
# 或者local newarray=($*) 给局部数组赋值
local newarray=(`echo $*`)
# $#:代表传入参数的个数
local i
for((i=0;i<$#;i++))
do
outarray[$i]=$((${newarray[$i]}*5))
done
echo "${outarray[*]}"
}
array ${num[*]}
[root@centos7 shell]# bash testarray.sh
all parameters: 1 2 3
5 10 15
函数位置参数与脚本程序的位置参数。
函数的位置参数:在函数后面加的位置参数。
脚本程序的位置参数:在执行脚本程序时,后面加的参数。
1
2
3
4函数接受位置参数:$1,$2,...$n
函数接收数组变量 $* 或 $@
函数将接收到的所有参数赋值给数组 newarray=($*)
函数获取参数的个数 $#eg1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[root@centos7 shell]# cat testreturn.sh
!/usr/bin/bash
if [ $# -ne 3 ];then
echo "usage: `basename $0` par1 par2 par3"
exit
fi
fun3()
{
echo "$(($1 * $2 * $3))"
}
函数内部的参数,$1传递给$1,$2传递给$2, $3传递给$3
result=`fun3 $1 $2 $3`
echo "result is : $result"
[root@centos7 shell]# bash testreturn.sh 1 2 3
result is : 6eg2:往函数中传数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22[root@centos7 shell]# cat testarray.sh
!/usr/bin/bash
num=(1 2 3 4 5)
输出数组的元素
echo "${num[@]}"
array()
{
# 默认是全局变量,在不同函数之间可以使用,若只是在函数内部生效加local
factorial=1
# 如果使用$*则不需要加双引号
for i in "$@"
do
factorial=$[factorial * $i]
done
echo "$factorial"
}
或写成:array ${num[*]}
array ${num[@]}
[root@centos7 shell]# bash testarray.sh
1 2 3 4 5
120