--- title: "18-函数" created: 2025-11-25 tags: - 项目 aliases: - 函数 --- # 函数 bash中的函数类似于C/C++中的函数,但return的返回值与C/C++不同,返回的是exit code,取值为0-255,0表示正常结束。 如果想获取函数的输出结果,可以通过echo输出到stdout中,然后通过$(function\_name)来获取stdout中的结果。 函数的return值可以通过$?来获取。 命令格式: ```bash [function] func_name() { # function关键字可以省略 语句1 语句2 ... } ``` ## 不获取 return值和stdout值 示例 ```bash func() { name=yxc echo "Hello $name" } func ``` 输出结果: ```text Hello yxc ``` ## 获取 return值和stdout值 不写return时,默认return 0。 示例 ```bash func() { name=yxc echo "Hello $name" return 123 } output=$(func) ret=$? echo "output = $output" echo "return = $ret" ``` 输出结果: ```text output = Hello yxc return = 123 ``` ## 函数的输入参数 在函数内,$1表示第一个输入参数,$2表示第二个输入参数,依此类推。 注意:函数内的$0仍然是文件名,而不是函数名。 示例: ```bash func() { # 递归计算 $1 + ($1 - 1) + ($1 - 2) + ... + 0 word="" while [ "${word}" != 'y' ] && [ "${word}" != 'n' ] do read -p "要进入func($1)函数吗?请输入y/n:" word done if [ "$word" == 'n' ] then echo 0 return 0 fi if [ $1 -le 0 ] then echo 0 return 0 fi sum=$(func $(expr $1 - 1)) echo $(expr $sum + $1) } echo $(func 10) ``` 输出结果: ```text 55 ``` 为什么只输出55不输出其他的值:只要在 `$(func)` 这样的命令替换里,这个 `$()` 就会截获掉函数内所有 echo 写进 stdout 的值,使得这些 echo 的内容不再显示到屏幕上。在递归往回调用的过程中,上一层的 echo 会被这一层的 `sum=$(func $(expr $1 - 1))` 中的第一个 `$()` 捕获从而没有输出,而最后一层的 echo 会被函数外的 `echo $(func 10)` 的 `$()` 捕获,因此是函数外的 echo 输出的 55。如果你把函数外的 `echo $(func 10)` 改成 `func 10`,输出的 55 就是最后一层递归里 `echo $(expr $sum + $1)` 输出的。 ## 函数内的局部变量 可以在函数内定义局部变量,作用范围仅在当前函数内。 可以在递归函数中定义局部变量。 命令格式: ```bash local 变量名=变量值 ``` 例如: ```bash #! /bin/bash func() { local name=yxc echo $name } func echo $name ``` 输出结果: ```text yxc ``` 第一行为函数内的name变量,第二行为函数外调用name变量,会发现此时该变量不存在。 > [!warning] 函数使用注意事项 > - **先定义后调用**:bash 按行解释执行脚本,调用发生在定义之前会报 `command not found`(这与 C/C++ 需要前置声明的道理类似)。 > - 函数名与 C/C++ 标识符规则相同:字母、数字、下划线,不能以数字开头,且**不能与内置命令同名**(如 `cd`、`exit`),否则会覆盖内置行为。 > - 函数内同样可以使用默认变量一节的所有符号:`$#` 表示传入函数的参数个数,`$@` 表示所有参数,只有 `$0` 例外——它仍然是脚本文件名而不是函数名。 > - `local` 只能在函数内使用;在函数外写 `local` 会报错。递归函数中**务必**对会变的变量用 `local`,否则递归各层共享同名全局变量,结果会错乱。 --- **项目分区导航**:[[17-循环语句|循环语句]] ⬅️ | 18-函数 | ➡️ [[19-exit命令|exit命令]]