Shell脚本编程(15)之数组变量和函数

Shell脚本编程(15)之数组变量和函数

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

本部分内容参考自《Linux命令行与shell脚本编程大全 第3版》。

数组变量

变量有一个很酷的特性就是,它们可作为数组使用。数组是能够存储多个值的变量。这些值可以单独引用,也可以作为整个数组来引用。
要给某个变量设置多个值,可以把值放在括号里,值与值之间用空格分隔。

$ mytest=(one two three four five)

没什么特别的地方。如果你想把数组像普通的变量那样显示,你会失望的。

$ mytest=(one two three four five)
$ echo $mytest
one

只有数组的第一个值显示出来了。要引用一个单独的数组元素,就必须用代表它在数组中位置的数值索引值。索引值要用方括号括起来。

$ echo ${mytest[2]}
three

要显示整个数组变量,可用星号作为通配符放在索引值的位置。

$ echo ${mytest[*]}
one two three four five

也可以改变某个索引值位置的值。

$ mytest[2]=seven
$ echo ${mytest[*]}
one two seven four five

甚至能用 unset 命令删除数组中的某个值,但是要小心,这可能会有点复杂。看下面的例子。

$ unset mytest[2]
$ echo ${mytest[*]}
one two four five
$ echo ${mytest[2]}

$ echo ${mytest[3]}
four

这个例子用 unset 命令删除在索引值为 2 的位置上的值。显示整个数组时,看起来像是索引里面已经没这个索引了。但当专门显示索引值为 2 的位置上的值时,就能看到这个位置是空的。
最后,可以在 unset 命令后跟上数组名来删除整个数组。

$ unset mytest
$ echo ${mytest[*]}

有时数组变量会让事情很麻烦,所以在 shell 脚本编程时并不常用。对其他 shell 而言,数组变量的可移植性并不好,如果需要在不同的 shell 环境下从事大量的脚本编写工作,这会带来很多不便。

向函数传递数组参数

向脚本函数传递数组变量的方法会有点不好理解。将数组变量当作单个参数传递的话,它不会起作用。

$ cat test9.sh 
#!/bin/bash
function testit {
	echo "The parameters are: $@"
	thisarray=$1
	echo "The received array is ${thisarray[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
testit $myarray
$ ./test9.sh 
The original array is: 1 2 3 4 5
The parameters are: 1
The received array is 1

如果你试图将该数组变量作为函数参数,函数只会取数组变量的第一个值。
要解决这个问题,你必须将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用。在函数内部,可以将所有的参数重新组合成一个新的变量。下面是个具体的例子。

$ cat test10.sh 
#!/bin/bash
function testit {
	local newarray
	newarray=(`echo "$@"`)
	echo "The new array value is: ${newarray[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is ${myarray[*]}"
testit ${myarray[*]}
$ ./test10.sh 
The original array is 1 2 3 4 5
The new array value is: 1 2 3 4 5

该脚本用 $myarray 变量来保存所有的数组元素,然后将它们都放在函数的命令行上。该函数随后从命令行参数中重建数组变量。在函数内部,数组仍然可以像其他数组一样使用。

$ cat test11.sh 
#!/bin/bash
function addarray {
	local sum=0
	local newarray
	newarray=($(echo "$@"))
	for value in ${newarray[*]}
	do
		sum=$[ $sum + $value ]
	done
	echo $sum
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
arg1=$(echo ${myarray[*]})
result=$(addarray $arg1)
echo "The result is $result"
$ ./test11.sh 
The original array is: 1 2 3 4 5
The result is 15

addarray 函数会遍历所有的数组元素,将它们累加在一起。你可以在 myarray 数组变量中放置任意多的值,addarry 函数会将它们都加起来。

从函数返回数组

从函数里向 shell 脚本传回数组变量也用类似的方法。函数用 echo 语句来按正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组变量中。

$ cat test12.sh 
#!/bin/bash
function arraydblr {
	local origarray
	local newarray
	local elements
	local i
	origarray=($(echo "$@"))
	newarray=($(echo "$@"))
	elements=$[ $# - 1 ]
	for (( i = 0; i <= $elements; i++ ))
	{
		newarray[$i]=$[ ${origarray[$i]} * 2 ]
	}
	echo ${newarray[*]}
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
arg1=$(echo ${myarray[*]})
result=($(arraydblr $arg1))
echo "The new array is: ${result[*]}"
$ ./test12.sh 
The original array is: 1 2 3 4 5
The new array is: 2 4 6 8 10

该脚本用 $arg1 变量将数组值传给 arraydblr 函数。 arraydblr 函数将该数组重组到新的数组变量中,生成该输出数组变量的一个副本。然后对数据元素进行遍历,将每个元素值翻倍,并将结果存入函数中该数组变量的副本。
arraydblr 函数使用 echo 语句来输出每个数组元素的值。脚本用 arraydblr 函数的输出来重新生成一个新的数组变量。

练习

1、生成 10 个随机数保存于数组中,并找出其最大值和最小值。

#!/bin/bash
#
declare -a rand
declare -i max=0

for i in {0..9};do
	rand[i]=$RANDOM
	echo ${rand[$i]}
	[ ${rand[$i]} -gt $max ] && max=${rand[$i]}
done
echo "Max:$max"

2、定义一个数组,数组中的元素是 /var/log 目录下所有以 .log 结尾的文件,要统计其下标为偶数的文件中的行数之和。

#!/bin/bash
declare -a files
files=(/var/log/*.log)
declare -i lines=0

for i in $(seq 0 $[${#files[*]}-1]);do
	if [ $[$i%2] -eq 0 ];then
		let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
	fi
done

echo "Lines:$lines"

3、生成 10 个随机数存于数组中,升序排序。

#!/bin/bash
declare -a nums
declare -i t
for i in {0..9};do
    nums[$i]=$RANDOM
    echo ${nums[$i]}
done

for ((i=0;i<${#nums[@]};i++));do
    for ((j=${#nums[@]}-1;j>i;j--));do
        if [[ ${nums[j]} -lt ${nums[j-1]} ]];then
            t=${nums[j]}
            nums[j]=${nums[j-1]}
            nums[j-1]=$t
        fi
    done
done
echo "排序后:${nums[@]}"

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/shell-15.html

Buy me a cup of coffee ☕.