shell函数
创始人
2024-05-24 17:24:01
0

文章目录

    • 六、函数和数组
      • 6.1 函数
        • 6.1.1什么是函数
        • 6.1.2 函数语法
        • 6.1.3 函数的调用
        • 6.1.4 函数的返回值
        • 6.1.5 函数案例
        • 6.1.6 函数库文件
        • 6.1.7 递归函数
      • 6.2 数组
        • 6.2.1 定义数组
        • 6.2.2 数组操作
        • 6.2.3 数组案例

六、函数和数组

6.1 函数

函数几乎是学习所有的程序设计语言时都必须过的一关。对于学习过其他的程序语言的用户来说,函数可能并不陌生。但是Shell中的函数与其他的程序设计语言的函数有许多不同之处。

6.1.1什么是函数

通俗地讲,所谓函数就是将一组功能相对独立的代码集中起来,形成一个代码块,这个代码可以完成某个具体的功能。从上面的定义可以看出,Shell中的函数的概念与其他语言的函数的概念并没有太大的区 别。从本质上讲,函数是一个函数名到某个代码块的映射。也就是说,用户在定义了函数之后,就可以通过函数名来调用其所对应的一组代码。

使用shell函数优势
• 1、把相同的程序段定义为函数,可以减少整个程序段代码量,提升开发效率。
• 2、增加程序段可读性、易读性,提升管理效率。
• 3、可以实现程序功能模块化,使得程序具备通用性(可移植性)。

6.1.2 函数语法

function 函数名() { 指令 return 
} 

简化写法1:

function 函数名 { 指令 return 
} 

简化写法2:

函数名() { 指令 return 
}

6.1.3 函数的调用

在Shell中,函数调用的基本语法如下:

function_name param1 param2 … 

在上面的语法中,function_name表示函数名称,其后面跟的param1、param2…表示函数的参数。

Shell的函数参数的语法比较特殊。实际上,Shell将脚本参数和函数参数做了统一地处理。也就是说, Shell采用了相同的方法来处理脚本的参数和函数参数。

(1)调用函数:直接执行函数名即可。

函数名

(2)带参数的函数执行方法:

函数名 参数

与Shell脚本一样,用户可以在Shell函数中使用位置变量来获取参数值。例如,$0表示脚本名称, $#来 获取函数的参数,$1表示第1个参数,$2表示第2个参数等,依次类推,另外用户还可以通过系统变量 $@和 $*获取所有参数的值

[root@localhost test6]# vim func.sh 
#!/bin/bash 
func() 
{ echo "the function has $# parameters" echo "all parameters are $*" echo "all parameters are $@" echo "the script's name is $0" echo "the first parameter is $1" 
} 
func hello world 
[root@localhost test6]# bash func.sh 
the function has 2 parameters 
all parameters are hello world 
all parameters are hello world 
the script's name is func.sh 
the first parameter is hello 

6.1.4 函数的返回值

首先,用户可以使用return语句来返回某个数值,这与绝大部分的程序设计语言是相同的。但是,在Shell中,return语句只能返回某个0~255之间的整数值。

在函数中,用户将需要返回的数据写入到标准输出(stdout),通常这个操作是使用echo语句来完成的。然后在调用程序中将函数的执行结果赋给一个变量。这种做法实际上就是命令替换的一个变种。

例:

[root@localhost test6]# vim length.sh 
#!/bin/bash 
length() 
{ str=$1 result=0 if [ "$1" != "" ];then result=${#str} fi echo "$result" 
} 
len=$(length "abcd12") 
echo "the string's length is $len" 
[root@localhost test6]# bash length.sh 
the string's length is 6

6.1.5 函数案例

示例1:写一个脚本,判定192.168.0.200-192.168.0.254之间的主机哪些在线。
要求:
• 1、使用函数来实现一台主机的判定过程;
• 2、在主程序中来调用此函数判定指定范围内的所有主机的在线情况。直接使用函数实现
方法一:直接使用函数实现(无参数,无返回值)

[root@localhost test6]# vim online_host.sh 
#!/bin/bash 
online() { 
for i in {200..254};do if ping -c 1 192.168.0.$i &>/dev/null then echo "192.168.0.$i is up" else echo "192.168.0.$i is down" fi 
done 
} 
online 

方法二:使用函数传参(有参数,无返回值)

[root@localhost test6]# vim online_host1.sh 
#!/bin/bash 
online() { if ping -c 1 $1 &>/dev/null then echo "$1 is up" else echo "$1 is down" fi 
} for i in {200..254} 
do online 192.168.0.$i 
done 

方法三:使用函数返回值判断(有参数,有返回值)

[root@localhost test6]# vim online_host2.sh 
#!/bin/bash 
online() { 
if ping -c 1 $1 >/dev/null 
then return 0 
else return 1 
fi 
} for i in {200..254} 
do online 192.168.0.$i if [ $? -eq 0 ];then echo "192.168.0.$i is up" else echo "192.168.0.$i is down" fi 
Done

示例2:写一个脚本,使用函数完成
• 1、函数能够接受一个参数,参数为用户名;
○ 判断一个用户是否存在
○ 如果存在,就返回此用户的shell和UID;并返回正常状态值;
○ 如果不存在,就说此用户不存在;并返回错误状态值;
• 2、在主程序中调用函数;

[root@localhost test6]# vim user_mess.sh 
#!/bin/bash 
user() { if id $1 &>/dev/null then echo "`grep ^$1 /etc/passwd | cut -d: -f3,7`" return 0 else echo "$1 does not exist" return 1 fi 
} read -p "please input username:" username 
until [ "$username" = "quit" -o "$username" = "exit" -o "$username" = "q" ] 
do user $username if [ $? == 0 ];then read -p "please input again:" username else read -p "no $username,please input again:" username fi 
done 
[root@localhost test6]# bash user_mess.sh 
please input username:redhat 
1000:/bin/bash 
please input again:jkl 
jkl does not exist 
no jkl,please input again:exit

6.1.6 函数库文件

为了方便地重用这些功能,可以创建一些可重用的函数。这些函数可以单独地放在函数库文件中。
• 函数库文件定义:
创建一个函数库文件的过程非常类似于编写一个Shell脚本。脚本与库文件之间的唯一区别在于函数库文件通常只包括函数,而脚本中则可以既包括函数和变量的定义,又包括可执行的代码。此处所说的可执行代码,是指位于函数外部的代码,当脚本被载入后,这些代码会立即被执行,毋需另外调用。
• 函数库文件的调用
当库文件定义好之后,用户就可以在程序中载入库文件,并且调用其中的函数。在Shell中,载入库文件的命令为.,即一个圆点,其语法如下:

. filename 

其中,参数filename表示库文件的名称,必须是一个合法的文件名。库文件可以使用相对路径,也可以使用绝对路径。另外,圆点命令和库文件名之间有一个空格。

6.1.7 递归函数

Linux的Shell也支持函数的递归调用。也就是说,函数可以直接或者间接地调用自身。在函数的递归调用中,函数既是调用者,又是被调用者。 递归函数的调用过程就是反复地调用其自身,每调用一次就进入新的一层。
示例:根据用户输入的数值计算该数的阶乘

[root@localhost test6]# vim fact.sh 
#!/bin/bash 
fact() 
{ local n="$1" if [ "$n" -eq 0 ] then result=1 else let "m=n-1" fact "$m" let "result=$n * $result" fi 
} 
fact "$1" 
echo "Factorial of $1 is $result" 
[root@localhost test6]# bash fact.sh 0 
Factorial of 0 is 1 
[root@localhost test6]# bash fact.sh 5 
Factorial of 5 is 120 

注意:默认情况下,除了与函数参数关联的特殊变量之外,其他所有的变量都有全局的有效范围。另外,在函数内部,如果没有使用local关键字进行修饰,那么函数中的变量也是全局变量。
例1:函数的变量是全局变量

[root@localhost test6]# cat global.sh 
#!/bin/bash 
var="hello world" 
func() 
{ var="orange" echo $var var2="hello" 
} 
echo "$var" 
func 
echo "$var" 
echo "$var2" 
[root@localhost test6]# ./global.sh 
hello world 
orange 
orange 
hello

例2:函数的变量使用local指定为局部变量

[root@localhost test6]# cat 7.sh 
#!/bin/bash 
var="hello world" 
func() 
{ local var="orange" echo "$var" local var2="hello" 
} 
echo "$var" 
func 
echo "$var" 
echo "$var2" 
[root@localhost test6]# ./7.sh 
hello world 
orange 
hello world 

6.2 数组

所谓数组,是指将具有相同类型的若干变量按照一定的顺序组织起来的一种数据类型。Shell语言对于数组的支持非常强大。在Shell中,用户可以通过多种方式来创建一个数组。

6.2.1 定义数组

• 定义数组 

方法一:用小括号将变量值括起来赋值给数组变量,每个变量之间要用空格进行分隔。

array=(value1 value2 value3 ... ) 

方法二:用小括号将变量值括起来,同时采用键值对的形式赋值。当通过键值对定义数组时,用户所提供的键值对中的元素索引不一定是连续的,可以任意指定要赋值的元素的索引。之所以可以这样操作,是因为用户已经显式指定了索引,Shell就可以知道值和索引的对应关系。

array=([0]=one [1]=two [2]=three ... [n]=valuen) 

方法三:分别定义数组变量的值

array[0]=a;array[1]=b;array[2]=c 

方法四:动态的定义变量,并使用命令的输出结果作为数组的内容。

array=(命令)

方法五:通过declare语句定义数组

declare -a array

• 定义关联数组:关联数组使用字符串作为下标,而不是整数,这样可以做到见名知意。不同于普通数组,关联数组必须使用带有 -A 选项的 declare 命令创建
方法一:一次赋一个值

[root@localhost ~]# declare -A array [root@localhost ~]# array[shuju1]=apple [root@localhost ~]# array[shuju2]=banana [root@localhost ~]# echo ${array[*]} banana apple 

方法二:一次赋多个值

[root@localhost ~]# declare -A a [root@localhost ~]# a=([index1]=tom [index2]=jack [index3]=alice) [root@localhost ~]# echo ${a[@]} tom jack alice 

6.2.2 数组操作

获取所有元素:

# echo ${array[*]}             # *和@ 都是代表所有元素 
获取元素下标: 
# echo ${!array[@]} 
# echo ${!array[*]} 
获取数组长度: 
# echo ${#array[*]} 
# echo ${#array[@]} 
获取第一个元素: 
# echo ${array[0]} 
添加元素: 
# array[3]=d 
添加多个元素: 
# array+=(e f g) 
以切片方式获取部分数组元素:(用户得到的是一个空格隔开的多个元素值组成的字符串) 
${array[@|*]:start:length} 
删除第一个元素: 
# unset array[0] # 删除会保留元素下标 
删除数组: 
# unset array 

遍历数组:
• 方法 1:

#!/bin/bash IP=(192.168.1.1 192.168.1.2 192.168.1.3) for ((i=0;i<${#IP[*]};i++)); do echo ${IP[$i]} done # bash test.sh 192.168.1.1 192.168.1.2 192.168.1.3 

• 方法 2:

#!/bin/bash IP=(192.168.1.1 192.168.1.2 192.168.1.3) for host_ip in ${IP[*]}; do echo $IP Done

6.2.3 数组案例

1、从“标准输入”读入n次字符串,每次输入的字符串保存在数组array里

[root@localhost test6]# vim str.sh 
i=0 
n=5 
while [ "$i" -lt $n ];do 
echo "please input strings...`expr $i + 1`" 
read array[$i] 
b=${array[$i]} 
echo "$b" 
i=`expr $i + 1` 
done 
[root@localhost test6]# bash str.sh 
please input strings...1 
a 
a 
please input strings...2 
fa 
fa 
please input strings...3 
fa 
fa 
please input strings...4 
few 
few 
please input strings...5 
wwwwwwwef 
wwwwwwwef 

2、将字符串里的字母逐个放入数组,并输出到“标准输出”

[root@localhost test6]# vim letter.sh 
chars='ajfkalfjoiweqqef' 
for ((i=0;i<${#chars};i++));do 
array[$i]=${chars:$i:1} 
echo ${array[$i]} 
done 

说明:KaTeX parse error: Expected '}', got 'EOF' at end of input: {chars:i:1},表示从chars字符串的 $i 位置开始,获取 1 个字符

3、把1-3这3个数字存到数组里,分别乘以8然后依次输出。

[root@localhost test6]# vim number.sh 
#!/bin/bash 
array=(`seq 3`) 
for ((i=0;i<${#array[@]};i++)) 
do 
echo $[${array[$i]}*8] 
echo $((${array[$i]}*8)) 
result=let "$array[$i] * 8" 
echo $result 
echo `expr ${array[$i]} * 8` 
done 
[root@localhost test6]# bash number.sh 
8 
16 
24 

4、打印下面这句话中字母数不大于6的单词:

	• cat is favorite to eat fish 
[root@localhost test6]# vim word.sh 
#!/bin/bash 
array=(cat is favorite to eat fish) 
for i in ${array[*]} 
do 
if [ ${#i} -lt 6 ] 
then 
echo $i 
fi 
done 
[root@localhost test6]# bash word.sh 
cat 
is 
to 
eat 
fish 

练习:
1、编写函数,实现打印绿色OK和红色FAILED
判断是否有参数,存在为Ok,不存在为FAILED
2、编写函数,实现判断是否无位置参数,如无参数,提示错误
3、编写函数实现两个数字做为参数,返回最大值
4、编写函数,实现两个整数位参数,计算加减乘除。
5、将/etc/shadow文件的每一行作为元素赋值给数组
6、使用关联数组统计文件/etc/passwd中用户使用的不同类型shell的数量
7、使用关联数组按扩展名统计指定目录中文件的数量

在这里插入图片描述

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...