shell脚本入门——函数

本文介绍了在Shell脚本中使用函数的基本概念,包括创建和调用函数、函数的返回值、函数中变量的使用,以及文件包含方法。通过实例解析了函数的默认退出状态码、return命令设置退出状态码、向函数传递参数、局部和全局变量的差异,以及文件包含的语法和注意事项。旨在帮助读者掌握Shell脚本中函数的运用。
摘要由CSDN通过智能技术生成

第1关:基本的脚本函数

任务描述

本关任务:掌握函数的创建和使用方法。

相关知识

函数是一个脚本代码块,你可以为其命名并在代码中任何位置重用。要在脚本中使用该代码块时,只要使用所起的函数名就行了(这个过程称为调用函数)。本关将会介绍如何在 shell 脚本中创建和使用函数。

创建函数
有两种格式可以用来在 bash shell 脚本中创建函数。

第一种格式采用关键字 function,后跟分配给该代码块的函数名。
function name {
commands
}
参数说明:

name 属性定义了赋予函数的唯一名称。脚本中定义的每个函数都必须有一个唯一的名称。
commands 是构成函数的一条或多条 bash shell 命令。在调用该函数时,bash shell 会按命令在函数中出现的顺序依次执行,就像在普通脚本中一样。
定义函数的第二种格式更接近于其他编程语言中定义函数的方式。
name() {
commands
}
函数名后的空括号表明正在定义的是一个函数。这种格式的命名规则和之前定义 shell 脚本函数的格式一样。

使用函数
【实例1】要在脚本中使用函数,只需要像其他 shell 命令一样,在行中指定函数名就行了。
已知 cat test.sh 显示内容如下:

#!/bin/bash

using a function in a script

function func1 {
echo “This is an example of a function”
}
count=1
while [ c o u n t − l e 5 ] d o f u n c 1 c o u n t = count -le 5 ] do func1 count= countle5]dofunc1count=[ $count + 1 ]
done
echo “This is the end of the loop”
func1 # 指定函数名即可调用函数
echo “Now this is the end of the script”
执行输出结果如下:

This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is the end of the loop
This is an example of a function
Now this is the end of the script
每次引用函数名 func1 时,bash shell 会找到 func1 函数的定义并执行你在那里定义的命令。
【实例2】函数的调用要在函数定义之后使用,否则会报错。

#!/bin/bash
echo “hello function”
fun1
fun1(){
echo “i am func1”
}
执行结果如下:

bash a.sh

hello function
a.sh: line 6: fun1: command not found
【实例3】函数名必须是唯一的,否则也会有问题。如果你重定义了函数,新定义会覆盖原来函数的定义,这一切不会产生任何错误消息。

#!/bin/bash
fun1(){
echo “i am func1”
}
fun1(){
echo “i am new func1”
}
fun1
执行结果如下:

i am new func1
编程要求
在右侧编辑器 Begin-End 区间补充代码,调用 welcome 函数输出指定内容。

测试说明

补全脚本之后,点击评测按钮,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。

开始你的任务吧,祝你成功!

Key:

#!/bin/bash

hello(){
	echo "hello,function!"
}

welcome(){
	echo "welcome to function world!"
}

####补全代码调用welcome函数输出指定内容
#########  Beging #########
welcome

########    End    #########

第2关:函数返回值

任务描述

本关任务:学习掌握什么是 shell 函数的返回值。

相关知识

bash shell 会把函数当作一个小型脚本,运行结束时,会返回一个退出状态码。有 3 种不同的方法来为函数生成退出状态码。

默认退出状态码
默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码。在函数执行结束后,可以用标准变量$?来确定函数的退出状态码。
【实例1】已知 test1.sh 脚本内容如下:

#!/bin/bash
func1() {
echo “trying to display a non-existent file”
ls -l badfile
}
echo "testing the function: "
func1
echo “The exit status is: $?”
运行脚本 bash test1.sh 执行结果如下:

testing the function:
trying to display a non-existent file
ls: cannot access badfile: No such file or directory
The exit status is: 2
函数的退出状态码是 2,这是因为函数中的最后一条命令没有成功运行。但你无法知道函数中其他命令中是否成功运行。带着这个疑问再看下面的例子:

【实例2】已知 test2.sh 脚本内容如下:

#!/bin/bash
func1() {
ls -l badfile
echo “trying to display a non-existent file”

}
echo "testing the function: "
func1
echo “The exit status is: $?”
运行脚本 bash test1.sh 执行结果如下:

testing the function:
ls: cannot access badfile: No such file or directory
trying to display a non-existent file
The exit status is: 0
这次,由于函数最后一条语句 echo 运行成功,该函数的退出状态码就是 0,尽管其中有一条命令并没有正常运行。由此可见,使用函数的默认退出状态码,来判断函数是否正常运行是很危险的。幸运的是,有几种办法可以解决这个问题。

return 命令
bash shell 使用 return 命令退出函数,并返回特定的退出状态码。return 命令允许指定一个整数值来定义函数的退出状态码,从而提供了一种简单的途径来设定函数退出状态码。
【实例3】已知 test3.sh 脚本的内容如下:

#!/bin/bash
func1() {
ls -l badfile
echo “trying to display a non-existent file”
return 20
}
echo "testing the function: "
func1
echo “The exit status is: $?”
执行bash test.sh显示如下:

testing the function:
ls: cannot access badfile: No such file or directory
trying to display a non-existent file
The exit status is: 20
这一次变量$?返回的结果是 20,而按照默认的返回 $? 应该是 0,因为函数的最后一条命令正确执行。

作答要求

根据相关知识,按照要求完成右侧选择题任务。作答完毕,通过点击“测评”,可以验证答案的正确性。

Key:

在这里插入图片描述


第3关:函数中使用变量

任务描述

本关任务:掌握函数传递参数的方法以及如何处理变量。

相关知识

向函数传递参数
我们在 shell 变量那个实训,介绍过了一些特殊变量 $0、 1 、 1、 1# 等。在 shell 中,函数可以使用标准的参数环境变量来表示命令行上传给函数的参数。例如,函数名会在$0变量中定义,函数命令行上的任何参数都会通过$1、 2 等定义。也可以用特殊变量 2等定义。也可以用特殊变量 2等定义。也可以用特殊变量#,来判断传给函数的参数数目。请参考实例 1:

【实例1】已知脚本 test.sh 的内容如下:

function addem {
if [ $# -eq 0 ] || [ $# -gt 2 ] # 判断传递给函数的参数个数
then
echo -1
elif [ $# -eq 1 ]
then
echo $[ $1 + $1 ]
else
echo $[ $1 + KaTeX parse error: Expected 'EOF', got '}' at position 11: 2 ] fi }̲ echo -n "Addi…(addem 10 15)
echo v a l u e e c h o − n " L e t ′ s t r y a d d i n g j u s t o n e n u m b e r : " v a l u e = value echo -n "Let's try adding just one number: " value= valueechon"Letstryaddingjustonenumber:"value=(addem 10)
echo v a l u e e c h o − n " N o w t r y i n g a d d i n g n o n u m b e r s : " v a l u e = value echo -n "Now trying adding no numbers: " value= valueechon"Nowtryingaddingnonumbers:"value=(addem)
echo v a l u e e c h o − n " F i n a l l y , t r y a d d i n g t h r e e n u m b e r s : " v a l u e = value echo -n "Finally, try adding three numbers: " value= valueechon"Finally,tryaddingthreenumbers:"value=(addem 10 15 20)
echo $value
输出结果如下:

Adding 10 and 15: 25
Let’s try adding just one number: 20
Now trying adding no numbers: -1
Finally, try adding three numbers: -1
这段脚本的意思是:脚本中的 addem 函数首先会检查脚本传给它的参数数目。如果没有任何参数,或者参数多于两个,addem 会返回值 -1;如果只有一个参数,addem 会将参数与自身相加;如果有两个参数,addem 会将它们进行相加。

注意:由于函数使用特殊参数环境变量作为自己的参数值,因此它无法直接获取脚本在命令行中的参数值。下面的【实例2】将会运行失败。

【实例2】:已知 test2.sh 的内容如下:

function badfunc1 {
echo $[ $1 * $2 ]
}
badfunc1
我在命令行执行 bash test2.sh 10 3,发现脚本报错:

[root@pre-host-work02 opt]# bash a.sh 1 10
a.sh: line 3: * : syntax error: operand expected (error token is "* ")
尽管函数 badfunc1 也使用了 $1 和 $2 变量,但它们和脚本主体中的 $1 和 $2 变量并不相同。要在函数中使用这些值,必须在调用函数时手动将它们传过去。我们把脚本改动如下:

function badfunc1 {
echo $[ $1 * $2 ]
}
badfunc1 $1 $2

通过将$1和$2变量传给函数,它们就能跟其他变量一样供函数使用了,我在命令行执行 bash test2.sh 10 3,结果符合预期:

[root@pre-host-work02 opt]# bash a.sh 10 3
30
函数中处理变量
函数使用两种类型的变量:

全局变量
局部变量
全局变量
全局变量是在 shell 脚本中任何地方都有效的变量。如果你在脚本的主体部分定义了一个全局变量,那么可以在函数内读取它的值。类似地,如果你在函数内定义了一个全局变量,可以在脚本的主体部分读取它的值。
默认情况下,你在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问,请看【实例3】。

【实列3】查看 test3.sh 内容,执行cat test3.sh 得到如下内容:

#!/bin/bash
function dbl {
value=$[ $value * 2 ]
}

value=450
dbl
echo “The new value is: $value”
执行脚本输出结果如下:

The new value is: 900
$value变量在函数外定义并被赋值。当 dbl 函数被调用时,该变量及其值在函数中都依然有效。如果变量在函数内被赋予了新值,那么在脚本中引用该变量时,新值也依然有效。但这其实很危险,尤其是如果你想在不同的 shell 脚本中使用函数的话。它要求你清清楚楚地知道函数中具体使用了哪些变量,包括那些用来计算非返回值的变量。请看【实例4】。

【实例4】:

#!/bin/bash
function func1 {
temp=$[ v a l u e + 5 ] r e s u l t = value + 5 ] result= value+5]result=[ $temp * 2 ]
}
temp=4
value=6
func1 # 这个时候全局变量temp=6+5及为11,result=22

echo “The result is $result”
if [ $temp -gt $value ]
then
echo “temp is larger”
else
echo “temp is smaller”
fi
执行脚本输出结果如下:

The result is 22
temp is larger
局部变量
无需在函数中使用全局变量,函数内部使用的任何变量都可以被声明成局部变量。要实现这一点,只要在变量声明的前面加上 local 关键字就可以了,比如local temp。或者也可以在变量赋值语句中使用 local 关键字:local temp=$[ $value + 5 ]。
local 关键字保证了变量只局限在该函数中。如果脚本中在该函数之外有同样名字的变量,那么 shell 将会保持这两个变量的值是分离的。现在你就能很轻松地将函数变量和脚本变量隔离开了,只共享需要共享的变量。

【实例5】:

#!/bin/bash

demonstrating the local keyword

function func1 {
local temp=$[ v a l u e + 5 ] r e s u l t = value + 5 ] result= value+5]result=[ $temp * 2 ]
}
temp=4
value=6
func1 #这个时候全局部变量temp=6+5,但是全局变量temp=4.
echo “The result is $result”
if [ $temp -gt $value ]
then
echo “temp is larger”
else
echo “temp is smaller”
fi
执行脚本输出结果如下:

The result is 22
temp is smaller
现在,在 func1 函数中使用 t e m p 变量时,并不会影响在脚本主体中赋给 temp 变量时,并不会影响在脚本主体中赋给 temp变量时,并不会影响在脚本主体中赋给temp变量的值。请重点分析【实例4】和【实例5】中的不同。

编程要求

本关不进行考核,希望大家能够真正的理解:

向函数传递变量的方法;
在函数中使用局部变量和全局变量的区别。 这两点非常重要,希望大家能够在命令行中自行练习本关【实例】中代码,能够充分的理解掌握这两点内容。

测试说明

无需大家进行补全代码操作,点击评测即可通关。

开始你的任务吧,祝你成功!

Key:

#**********   本小节目的,希望同学们能够理解局部,全局变量    *********#






#**********  请自己打开命令行自行编写脚本训练实例内容       *********#
#**********  无需补充代码点击评测 , 即可通关               *********#

第4关:函数中文件包含

任务描述

本关任务:掌握文件包含方法的使用。

相关知识

文件包含方法
在 C,C++,PHP 中都是用 include 来包含文件,Go 和 Java 使用 import 来包含(导入)包,而在 shell 中,很简单,只需要一个点.,然后跟着文件路径及文件名,或者使用source关键字也可以,注意文件路径可以使用绝对路径和相对路径。请看实例 1。

【实例1】已知在同一目录下,有 test1.sh 和 test2.sh 两个脚本,test1.sh 内容如下:

#!/bin/bash
url=“www.educoder.net”
同一目录下的 test2.sh 内容如下:

#!/bin/bash
. ./test1.sh # 第一个.是包含符号,第二个. 表示当前目录下。
# 这是采用相对路径包含的学法,记得中间要空格。
echo “编程平台地址是:$url”
在命令行执行bash test2.sh,大家想想看这个时候输出的是什么?
输出的结果如下:

编程平台地址是:www.educoder.net
注意:

变量的定义也要考虑局部变量和全局变量;
如实例1 所示 test1.sh 并不需要赋予执行权限;
注意包含文件的路径。
【实例2】同一目录下 test1.sh、test2.sh、test3.sh 内容如下:

[root@pre-host-work02 opt]# cat test1.sh
#!/bin/bash
test(){
url=‘www.educoder.net’
}
[root@pre-host-work02 opt]# cat test2.sh
#!/bin/bash
hello(){
echo “i am from test3.sh”
}
[root@pre-host-work02 opt]# cat test3.sh
#!/bin/bash
##包含多个文件时,一行智能写一个文件,分开写。
. ./test1.sh ##包含test1.sh ./test1.sh表示当前目录下
. ./test2.sh ##包含test2.sh ./test2.sh表示当前目录下
echo “编程平台:$url”
hello
在命令行执行bash test3.sh ,输出结果如下:

[root@pre-host-work02 opt]# bash test3.sh
编程平台:
i am from test3.sh
因为在 test1.sh 中 url 变量定义在函数内,即为局部变量,所以包含过来之后不能被调用;
test2.sh 中定义了函数 hello,在 test3.sh 通过. 的方式包含进来,通过函数名 hello 的调用,调用了 test2.sh 中的 hello()函数,输出“i am from test3.sh” 。
编程要求
本关任务包含了三个脚本文件,它们分别是 step4/t1.sh、step4/t2.sh 、 step4/main.sh,点击右侧“代码文件”即可查看,如下图所示:

根据要求补全 step4/t1.sh 代码。

根据要求补全 step4/main.sh 代码。

测试说明

补全脚本之后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。

开始你的任务吧,祝你成功!

Key:

t1.sh

#########   Begin  ##########

#1.请按照要求定义函数Hello ,函数Hello 执行的语句为  echo "文件包含test1.sh"
Hello(){
    echo "文件包含test1.sh"

}




#########   End    ##########


t2.sh

#!/bin/bash 

name="i am test2.sh"

main.sh

#!/bin/bash


##########  Begin ##########

#1.引用step4/目录下t1.sh t2.sh,将他们包含进来。

. step4/t1.sh

. step4/t2.sh


##########  End   ##########

#调用t1.sh中的Hello 函数
Hello

#输出t2.sh中的变量$name
echo  "hello:$name"

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只菜鸟呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值