Bash 函数
Bash 函数
Bash 函数和 Bash 脚本的各个方面都非常相似,其底层可能是同一个东西。
简介
函数(function)是可以重复使用的代码片段,有利于代码的复用。它与别名(alias)的区别是,别名只适合封装简单的单个命令,函数则可以封装复杂的多行命令。
我们可以将带有参数的命令设置一个别名,alias,所以别名也可以做简单的函数,比如查找特定文件之类的
函数总是在当前 Shell 执行,这是跟脚本的一个重大区别,Bash 会新建一个子 Shell 执行脚本。
如果函数与脚本同名,函数会优先执行。但是,函数的优先级不如别名,即如果函数与别名同名,那么别名优先执行。
shell 环境下同名的时候的优先级:别名 > 函数 > 脚本
Bash 函数定义的语法有两种。
|
|
上面代码中,fn
是自定义的函数名,括号里是不写参数的,函数代码就写在大括号之中。上面这两种写法是等价的。不过一般推荐第二种,带有 function 关键字,可读性好一些
我们在交互式 shell 中创建函数的时候,输入完
function test_fun() {
之后直接回车,不会直接执行,而是像 Here 文档一样,出现>
,直到输入}
,关于 Here 文档,请看《转义和引号》
删除一个函数,可以使用unset
命令。关于 unset 命令,请看《Bash 变量》的删除变量
小节
|
|
查看当前 Shell 已经定义的所有函数,可以使用declare
命令。关于 declare 命令,请看《Bash 变量》的declare 命令
小节
|
|
上面的declare
命令不仅会输出函数名,还会输出所有定义。输出顺序是按照函数名的字母表顺序。由于会输出很多内容,最好通过管道命令配合more
或less
使用。
declare
命令还支持查看单个函数的定义。
|
|
declare -F
可以输出所有已经定义的函数名,不含函数体。
|
|
简单实践如下:
|
|
调用时,就直接写函数名,参数跟在函数名后面。这种传参的方式跟脚本传参的默认方式一样
函数体里面的$1
表示函数调用时的第一个参数。其他几个变量比如$@
、$#
,其含义也跟在脚本中一样
简单实践如下:
|
|
参数变量
函数体内可以使用参数变量,获取函数参数。函数的参数变量,与脚本参数变量是一致的。
$1
~$9
:函数的第一个到第 9 个的参数。$0
:函数所在的脚本名。$#
:函数的参数总数。$@
:函数的全部参数,参数之间使用空格分隔。$*
:函数的全部参数,参数之间使用变量$IFS
值的第一个字符分隔,默认为空格,但是可以自定义。
如果函数的参数多于 9 个,那么第 10 个参数可以用${10}
的形式引用,以此类推。
此外注意,脚本传参是做不到传递数组变量的,只能做到将所有的数组元素挨个传入,然后再在脚本中组合成一个数组。
shift
命令可以改变脚本参数,每次执行都会移除脚本当前的第一个参数($1
),使得后面的参数向前一位,即$2
变成$1
、$3
变成$2
、$4
变成$3
,以此类推。
shift
命令可以接受一个整数作为参数,指定所要移除的参数个数,默认为1
。
此外,在方法中也可以使用 getopts 命令或者 getopt 命令,以-
或者--
的格式传入参数,跟脚本的传参方式基本无异。而且调用起来比脚本调用起来更加简洁
具体请看《Bash 脚本》的
脚本参数
小节。
简单实践如下:
创建function.sh
|
|
赋权后执行
|
|
return 命令
return
命令用于从函数返回一个退出码,这个退出码的范围为 0-255。函数执行到这条命令,就不再往下执行了,直接返回了。
|
|
函数将退出值返回给调用者。如果命令行直接执行函数,下一个命令可以用$?
拿到退出码的值。
|
|
return
后面不跟参数,只用于返回也是可以的。此时会返回函数体中最后一个命令的退出码。
|
|
具体请看《Bash 脚本》的
return 命令
小节
如果函数想返回除退出码以外的内容,则可以在函数体中通过 echo 语句中输出,然后用子命令拓展符号将调用方法的语句包起来,例如$(func param1 param2)
,这样就可以的获取函数中所有的 echo 语句返回的值,默认以 IFS 变量分割,甚至还可以通过()
包起来,成为数组。
关于子命令拓展,请看《Bash 的模式拓展》的
子命令拓展
小节关于数组,请看《Bash 数组》小节
简单实践如下:
|
|
传递参数到子脚本和方法中的时候无法传递数组类型,只能传递字符串类型,其实也就证明 Bash 中不存在单独的数组类型,只有字符串一个类型。
既然 Bash 没有数据结构,没有原始数据类型和对象类型这些东西,自然也就不存在什么值传递和引用传递的区别,
而这,这是 bash 的局限性。
全局变量和局部变量
Bash 函数体内直接声明的变量,属于全局变量,(在同一脚本中)方法外,甚至别的方法内部都可以读取。
而且函数体内不仅可以声明全局变量,还可以修改全局变量。
函数里面可以用local
命令声明局部变量。方法中的局部变量只在方法内部可以使用。
简单实践如下:
创建function_var.sh
|
|
赋权后执行:
|
|
local
命令声明的$gender
变量,只在函数体内有效,函数体外没有定义。
再次感觉方法调用起来比脚本调用起来更加简洁