Shell 脚本中的函数

通过之前发表的文章,相信大家对 Linux Shell 脚本的基本语法有了一定程度的了解,接下来几篇文章我将会介绍一些 Shell 脚本编程的一些高级语法,今天我们就从函数开始。

提到函数,相信有过编程基础的小伙伴都会了解一些,函数其实是我们编码的逻辑单元,无论我们用的面向过程的语言,还是面向对象的语言,函数都是编程中基本的内容。好的函数接口设计,清晰的函数逻辑,巧妙的函数提取,都是对程序员最基本的要求。

创建函数

bash shell中有两种方式创建函数;

1. 通过function 命名函数,格式为

function name {
commands
}
Shell 脚本中的函数

图1

2. 直接通过函数名来创建函数,格式为

name ( ) {
commands
}
Shell 脚本中的函数

图2

图1和图2的输出结果相同,为:

./my_script
this is function
this is function

注:在调用函数之前,函数首先要被定义过,也就是说在脚本编写过程中,函数应该在调用之前先被定义,否则会出现函数未定义的错误。其次同名函数如果重复定义,后定义的函数会覆盖之前定义的同名函数。

函数返回值

有时我们在调用函数式,需要通过函数的返回值来判断接下来程序的逻辑,在bash shell中函数通过退出状态码(退出状态码的定义在之前的文章中有介绍)实现函数返回值,并且提供了3种方式来返回函数的退出状态码。

1. 默认退出状态码:

默认状态下,函数通过最后一行命令的返回状态码作为整个函数的状态码返回。这种方式比较危险,可能函数中某些步骤的命令已经出错了,但是最后一行的命令却执行成功,此时作为整个函数的返回码是正确定,那么就掩盖掉错误了。

2. 使用return 语句

可以在函数尾部通过return 语句返回自定义的返回码,例如

function my_func {
value=1
echo "It is my function"
return $[$value+2]
}

my_func 函数返回状态码为3. 用return 返回状态码要注意,

  • 函数调用后要立即获取返回状态码
  • 状态码的取值范围为: 0~255。

3. 通过 echo 内容作为函数返回

Shell 脚本中的函数

图3

如上图,函数中通过 echo 将其后的内容做为返回值,调用函数后,会将输入的数值翻倍后作为函数输出保存到变量 result 中。

向函数中传递参数

bash shell 函数可以理解为小型脚本,之前的文章中我讲解过如何向脚本中传递参数,所以类似的,向函数中传递参数的方式是一样的。格式为

func1 $param1 $param2...

直接上例子:

Shell 脚本中的函数

图4

之前向脚本传递参数的讲解中,讲解了如何在脚本中获取参数值,其格式和函数获取参数值得方式一致,通过$0, $1.. 或去对应参数的值,$#获取参数个数。上面的例子中,通过$#判断函数参数个数,如果大于2个或者等于0个,则认为调用失败,返回-1 的状态码。如果参数是1个,则打印这个参数,如果参数刚好2个,则打印两个参数的和。对脚本参数传递有印象的小伙伴可能会有些疑虑,因为函数获取参数值的方式和脚本获取参数值得方式相同,都是通过 $1, $2 ... 来获取第一个,第二个参数的,那么函数的参数会不会覆盖脚本的参数呢?其实这里涉及到作用域的概念,可以裂解为同名但作用域不同。举例:

Shell 脚本中的函数

图5

如上图5, 函数 addem 中通过 $1, $2 来获取传入函数的参数值,函数体外,脚本通过$# 来获取传入脚本的参数个数,然后在then 语句后,通过$1, $2 来获取传递到脚本的参数,然后再将传递进脚本的参数通过调用函数 addem 传递进函数体内。虽然都是通过环境变量 $1, $2 来获取的参数,但是两个变量作用域并不相同,你可以把函数理解为脚本文件中的子脚本。所以没有问题。调用结果如下图6:

Shell 脚本中的函数

图6

变量的作用域

函数中使用的变量有两种类型:

  • 全局变量
  • 局部变量

全局变量:顾名思义就是脚本中和函数体内都可以引用的变量。默认情况下,脚本中,函数体外定义的任何变量都是全局变量,函数体内可以直接访问。例如

function my_func {
value=$[ $value + 5]
}
value=2
my_func
echo "The new value is: $value"

#调用脚本
输出结果为:
The new value is: 7

上面的例子中,value 在函数体外定义了,是全局变量,所以value值被改变了,在函数体内修改全局变量并不是一个好的主意,所以函数内使用全局变量要特别注意,否则可能会引起错误。

局部变量:函数体内任何变量都可以声明为局部变量,只需要在声明前加上 local 关键字即可。格式为:

local tmpVar

上例子

Shell 脚本中的函数

图7

输出为:

local value is: 20
the global value is: 10

从结果可以看出,局部变量 variable 的修改没有影响到全局变量的值。

数组作为函数参数

传递数组给函数,不能讲数组变量作为单独一个变量直接传递给数组,那样只会函数内只能方位到数组的第一个元素,这个原理和C/C++有些相似,C/C++中传递的是数组的指针,所以也只能访问到数组的第一个元素。bash shell 中可以通过将数组分解成单个的值进行传递。直接上例子:

Shell 脚本中的函数

图8

输出结果为:

the original array is 1 2 3 4 5
the sum result is: 15

数组作为函数返回

Shell 脚本中的函数

图9

输出为:

the original array is: 1 2 3 4 5
the new array is: 2 4 6 8 10

从图9看出,函数接受数组,并将数组中所有元素翻倍后返回。

创建库

在C/C++工程中,我们经常会将一些通用的函数放到独立的工程中,并将其生成库文件,也就是 lib 文件或者 dll 文件,这样一段函数就可以被不同工程调用,从而减少代码重复。bash shell 中也有类似的库应用,可以将函数创建成库文件,然后被不同的脚本调用。bash shell 中创建库文件的步骤如下:

1. 创建包含所需函数的脚本文件,如下图,创建一个名为 mylib 的库文件

Shell 脚本中的函数

名字为 mylib 的库文件

2. 在脚本中引用库文件,可以通过source 命令引入库文件到脚本中,source 有一个快捷别名,称为点操作符(dot operator),下图举例脚本中如何引用库文件。

Shell 脚本中的函数

图10

图10 为脚本文件,通过点操作符引入库文件,调用mylib中的addem 函数。


分享到:


相關文章: