shell函数需先定义后调用,不支持声明提升或自动跨文件加载;参数需加引号防拆分,用"$@"转发;return仅返回0–255状态码,结果需用命令替换捕获;变量默认全局,local非posix标准;set选项会延续生效。

Shell 函数不是“写完就能用”的东西,必须定义在调用之前,且参数和返回值的处理方式与主流编程语言差异明显——搞错顺序或忽略 $? 的时效性,函数就等于白写。
函数定义必须放在调用前,且不能跨文件自动加载
Shell 解释器是顺序执行的,遇到函数调用时,如果此前没看到该函数定义,就会报 command not found。不存在“声明提升”,也不支持像 Python 那样 import 一个函数文件后直接用。
- 定义必须出现在脚本靠前位置,通常放在
#!/bin/bash下方、任何调用语句之前 - 想复用函数?得用
source ./lib.sh或. ./lib.sh显式加载,且被加载的文件里也不能有调用语句(否则 source 时就执行了) - 别依赖
$SHELL环境变量来判断当前 shell 类型——它只记录登录时的默认 shell,实际可能是dash或zsh,而它们对函数语法的支持略有差异
$1、$2 是位置参数,但空格和引号会彻底改变行为
传参看着简单,但一旦参数含空格、星号、美元符等,不加引号就会被 shell 拆分或展开,导致 $2 拿到的不是你预期的值。
- 调用时写
myfunc "file name.txt" "*.log",函数内才能用$1安全拿到完整文件名 - 用
"$@"代替$*转发全部参数:前者保持每个参数的原始边界,后者会把所有参数拼成一个字符串再分割 -
$#是参数个数,但注意:如果调用时写了myfunc a b "" c,空字符串""仍算一个参数,$#为 4
return 只能返回 0–255 整数,$? 一读就失效
Shell 函数没法返回字符串或数组,return 唯一作用是设退出状态。而 $? 只保存上一条命令(包括函数调用)的结果,下一条命令一执行,它就被覆盖。
- 需要获取计算结果?用命令替换:
result=$(myfunc 10 20),前提是函数用echo输出,而不是return -
return 0表示成功,非 0 表示失败——这是 Unix 通用约定,别反过来用 - 别写
if myfunc; then ...; fi后还去查$?:此时if已经消费了返回值,$?是if自己的判断结果(0 或 1)
函数体内修改全局变量要小心作用域陷阱
Shell 没有局部变量概念(local 是 bash/zsh 特性,dash 不支持),所有变量默认全局。函数里改了 PATH 或 IFS,退出后依然生效。
- 要用
local var=value限定作用域,但得确认你的目标系统 shell 支持(#!/bin/sh脚本里尽量别用) - 避免重用常见变量名如
USER、HOME、PS1,哪怕只是临时赋值 - 函数中执行
cd后没配对cd -或保存原路径,会导致后续命令在错误目录下运行
最常被忽略的一点:函数体内的 set -e 或 set -u 会持续生效到函数结束之后,不是仅限函数内部。如果你在函数里开了严格模式,又没关,整个脚本余下部分都会受其影响。










