3.3 Shell函数

评论 0 浏览 0 2023-01-16

Shell函数是一种将命令分组以便以后执行的方法,它使用一个单独的名字来分组。当shell函数的名称被用作简单的命令名称时,与该函数名称相关的命令列表就会被执行。 Shell函数在当前的shell上下文中被执行;不会创建新的进程来解释它们。

函数是用这种语法声明的:

fname () compound-command [ redirections ]

function fname [()] compound-command [ redirections ]

这定义了一个名为fname的shell函数。保留词function是可选的。 如果提供了function保留词,那么括号是可选的。 该函数的主体复合命令(见5 复合命令)。该命令通常是一个括在{和}之间的list,但也可以是上面列出的任何复合命令。 如果使用了function保留词,但没有提供括号,建议使用大括号。 只要fname被指定为简单命令的名称,就会执行compound-command。当shell处于POSIX模式时(见6.11 Bash的POSIX模式),fname必须是一个有效的shell名称,并且不能与一个特殊的内置程序相同(见4.4 特殊的内建程序)。 在默认模式下,一个函数名称可以是任何不包含‘$’的未引用的shell单词。任何与shell函数相关的重定向(见3.6 重定向)都会在函数被执行时执行。 一个函数的定义可以用-f选项来删除unset内置程序(见4.1 Bourne Shell内置程序)。

除非发生语法错误或已经存在一个同名的只读函数,否则函数定义的退出状态为零。 当执行时,函数的退出状态是主体中最后执行的命令的退出状态。

请注意,由于历史原因,在最常见的用法中,包围函数主体的大括号必须用空格或换行符与主体隔开。 这是因为大括号是保留字,只有当它们与命令列表用空白或其他shell元字符隔开时,才会被识别出来。 另外,在使用大括号时,list必须用分号、‘&’或换行符来结束。

当一个函数被执行时,函数的参数在其执行过程中成为位置参数(见1 位置参数)。 扩展到位置参数数量的特殊参数‘#’被更新以反映这一变化。 特殊参数0保持不变。 当函数执行时,FUNCNAME变量的第一个元素被设置为函数的名字。

shell执行环境的所有其他方面在一个函数和它的调用者之间是相同的,除了以下这些例外:DEBUGRETURN陷阱不被继承,除非使用declare builtin为函数赋予了trace属性或使用set内建程序启用了-o functrace选项(在这种情况下,所有函数都继承DEBUGRETURN陷阱),ERR陷阱也不被继承,除非-o errtraceshell选项被启用。参见4.1 Bourne Shell内置程序,以了解对trap内建程序的描述。

FUNCNEST变量,如果设置为大于0的数值,则定义了一个最大的函数嵌套级别。函数的调用如果超过限制,就会导致整个命令的终止。

如果在一个函数中执行了内置命令return,那么该函数就会完成,并在函数调用后的下一条命令中恢复执行。 任何与RETURN陷阱相关的命令都会在恢复执行前执行。 当一个函数完成时,位置参数和特殊参数‘#’的值会恢复到它们在函数执行前的值。如果给了return一个数字参数,那就是函数的返回状态;否则,函数的返回状态就是return之前执行的最后一条命令的退出状态。

函数的局部变量可以用local内置函数来声明(局部变量)。 通常情况下,变量和它们的值在函数和它的调用者之间共享。 这些变量只对函数和它调用的命令可见。当一个shell函数调用其他函数时,这一点尤其重要。

在下面的描述中,当前作用域是指当前正在执行的函数。之前的作用域包括该函数的调用者,以此类推,一直到"全局"作用域,在这里shell没有执行任何shell函数。 因此,当前局部作用域的局部变量是在当前正在执行的函数中使用localdeclare内置变量所声明的变量。

局部变量"隐藏"了在先前作用域中声明的同名变量。例如,在一个函数中声明的局部变量隐藏了一个同名的全局变量:引用和赋值了局部变量,而全局变量没有被修改。 当函数返回时,全局变量再次可见。

shell使用动态作用域来控制变量在函数中的可见性。通过动态作用域,可见变量及其值是导致执行到达当前函数的函数调用序列的结果。函数看到的变量的值取决于它在其调用者中的值(如果有的话),无论该调用者是"全局"范围还是另一个shell函数。 这也是局部变量声明"隐藏"的值,也是函数返回时恢复的值。

例如,如果一个变量var在函数func1中被声明为局部变量,而func1调用了另一个函数func2,那么从func2中对var的引用将解析为来自func1的局部变量var,隐藏任何名为var的全局变量。

下面的脚本演示了这一行为。 当执行时,脚本显示

In func2, var = func1 local
func1()
{
    local var='func1 local'
    func2
}

func2()
{
    echo "In func2, var = $var"
}

var=global
func1

unset内置函数也使用相同的动态作用域:如果一个变量是当前作用域的局部变量,unset将解除它的设置;否则 unset 将引用在上述任何调用范围中找到的变量。 如果当前局部范围内的变量未设置,它将保持这种状态(显示为未设置),直到它在该作用域中被重置或直到函数返回。一旦函数返回,先前范围内的任何变量实例都将变得可见。如果unset作用于先前作用域中的一个变量, 一旦函数返回,先前范围内的任何变量实例都将变得可见(见下文localvar_unsetshell选项如何改变这种行为)。

函数名称和定义可以用declare (typeset)内置命令的-f选项列出(见4.2 Bash的内置命令)。 declaretypeset-F选项将只列出函数名称(如果extdebugshell选项被激活,还可以选择源文件和行号)。函数可以被导出,这样子shell进程(那些在执行单独的shell调用时创建的进程)就会自动用export内置的-f选项来定义它们(见4.1 Bourne Shell内置程序)。

函数可以是递归的。 FUNCNEST变量可以用来限制函数调用堆栈的深度,并限制函数调用的数量。 默认情况下,对递归调用的数量没有限制。

最后更新2023-02-20
0 个评论
上一篇: 3.2 Shell指令
下一篇: 3.4 shell参数
当前页面书签