位置参数
在 Shell 函数中,传递给函数的参数会被当作“位置参数”来处理,这与你在命令行直接执行脚本时传递参数的机制是完全一样的。

(图片来源网络,侵删)
$0: 函数名(或者脚本名)$1: 第一个参数$2: 第二个参数${10}: 第十个参数 (当参数个数 >=10 时,需要用花括号 括起来,避免 Shell 解析错误)- 所有参数的列表,每个参数都是独立的字符串,这是最常用的方式。
- 所有参数的列表,被看作一个单一的字符串,用第一个字符(通常是空格)连接。
- 参数的个数。
基本用法:按位置访问参数
这是最直接的方式,通过 $1, $2 等来访问每个参数。
示例:一个简单的加法函数
#!/bin/bash
# 定义一个函数,接收两个参数并计算它们的和
add() {
# 检查参数数量是否正确
if [ $# -ne 2 ]; then
echo "Usage: add <num1> <num2>"
return 1 # 返回一个非零值表示错误
fi
local sum=$(($1 + $2)) # 使用 local 声明局部变量,避免污染全局环境
echo "The sum of $1 and $2 is: $sum"
}
# --- 调用函数 ---
add 10 20
add 5 5
add 100 # 错误调用,参数不足
输出:
The sum of 10 and 20 is: 30
The sum of 5 and 5 is: 10
Usage: add <num1> <num2>
循环处理所有参数
当你不确定会有多少个参数,或者需要对每个参数执行相同的操作时, 和 for 循环是最佳组合。

(图片来源网络,侵删)
*关键区别: vs `$`**
for param in "$@": 这是推荐的方式。 会将每个参数作为一个独立的元素,即使参数本身包含空格,for循环也能正确处理。- *`for param in "$"
**: 不推荐用于循环。"*"` 会将所有参数合并成一个字符串,并用第一个字符(通常是空格)分隔,如果参数中有空格,这个方式会错误地分割参数。
示例:遍历并打印所有参数
#!/bin/bash
# 定义一个函数,打印所有传入的参数
print_all_params() {
echo "Function name: $0"
echo "Total arguments: $#"
echo "--- Printing all arguments ---"
# 推荐使用 "$@"
for param in "$@"; do
echo "Parameter: $param"
done
echo "--- End of printing ---"
}
# --- 调用函数 ---
print_all_params "Hello World" "Shell Scripting" "is fun"
输出:
Function name: ./your_script_name.sh
Total arguments: 3
--- Printing all arguments ---
Parameter: Hello World
Parameter: Shell Scripting
Parameter: is fun
--- End of printing ---
*对比:使用 `$` 的错误示例**

(图片来源网络,侵删)
# 错误的用法 for param in "$*"; do echo "Parameter: $param" done
输出(错误):
Parameter: Hello World Shell Scripting is fun
可以看到,所有参数被合并成了只有一个元素的长字符串。
将参数传递给其他命令或函数
有时,你的函数需要接收参数,然后将这些参数原封不动地传递给另一个外部命令或函数,这时, 再次派上用场。
示例:一个通用的“执行器”函数
#!/bin/bash
# 定义一个函数,它可以执行任何命令,并将所有参数传递给该命令
run_command() {
local cmd_name=$1
shift # 移除第一个参数(命令名),剩下的就是命令的参数
echo "Executing command: $cmd_name with parameters: $@"
# 检查命令是否存在
if command -v "$cmd_name" &> /dev/null; then
"$cmd_name" "$@" # 关键!使用 "$@" 来传递所有参数
else
echo "Error: Command '$cmd_name' not found."
fi
echo "------------------------------------"
}
# --- 调用函数 ---
run_command echo "Hello from" "run_command"
run_command ls -l /tmp
run_command git status
输出:
Executing command: echo with parameters: Hello from run_command
Hello from run_command
------------------------------------
Executing command: ls with parameters: -l /tmp
total 16
drwxr-xr-x 3 root root 220 Oct 26 10:30 ./
drwxr-xr-x 12 root root 340 Oct 26 10:30 ../
-rw-r--r-- 1 root root 0 Oct 26 10:30 test.txt
------------------------------------
Executing command: git with parameters: status
On branch main
...
------------------------------------
解释:
local cmd_name=$1: 将第一个参数赋值给cmd_name。shift: 这是一个重要的内置命令,它会将位置参数向左移动一位。$2变成$1,$3变成$2,以此类推,(参数个数)会减一,我们用它来移除已经处理过的命令名。"$cmd_name" "$@": 这行代码是核心。 展开后,会变成类似"echo" "Hello from" "run_command"的形式,从而将所有参数正确地传递给echo命令。
高级用法:使用 getopts 解析选项
如果你的函数需要处理类似命令行选项的参数(-f, -v, --help),那么使用 getopts 会比手动解析 $1, $2 更强大、更规范。
示例:一个带选项的函数
#!/bin/bash
# 定义一个函数,使用 getopts 解析 -f 和 -v 选项
process_file() {
local file=""
local verbose=false
# getopts 的格式: "f:v" 表示 -f 和 -v 是有效选项
# f: 后面没有冒号,表示这个选项本身不带参数
# v: 后面有冒号,表示这个选项需要一个参数 (-v value)
while getopts "f:v" opt; do
case $opt in
f)
file="$OPTARG"
;;
v)
verbose=true
;;
\?)
echo "Invalid option: -$OPTARG" >&2
return 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
return 1
;;
esac
done
# 移除 getopts 处理过的选项,剩下的就是位置参数
shift $((OPTIND - 1))
echo "--- Function Output ---"
echo "Verbose mode: $verbose"
echo "File specified: $file"
echo "Remaining arguments: $@"
echo "----------------------"
}
# --- 调用函数 ---
echo "Call 1:"
process_file -f "my_log.txt" -v "arg1" "arg2"
echo "Call 2:"
process_file -v -- This is a different style # 注意:getopts 默认不支持长选项如 --help
输出:
Call 1:
--- Function Output ---
Verbose mode: true
File specified: my_log.txt
Remaining arguments: arg1 arg2
----------------------
Call 2:
--- Function Output ---
Verbose mode: true
File specified:
Remaining arguments: -- This is a different style
----------------------
| 方法 | 用途 | 示例 | 备注 |
|---|---|---|---|
$1, $2, ... |
访问固定数量的特定参数 | echo "First: $1, Second: $2" |
简单直接,但参数数量必须固定。 |
| 获取参数总个数 | if [ $# -eq 0 ]; then ... |
用于参数数量校验。 | |
for param in "$@" |
推荐,遍历所有参数,保持参数独立性 | for p in "$@"; do ... |
能正确处理带空格的参数。 |
| *`for param in "$"`** | 不推荐,遍历所有参数,但将它们合并成一个字符串 | for p in "$*"; do ... |
容易因空格等字符而出错。 |
shift |
移除位置参数 | shift 2 # 移除前两个参数 |
常用于处理选项或传递参数给其他命令。 |
getopts |
解析单字符选项(如 -f, -v) |
while getopts "f:v" opt; do ... |
功能强大,是编写复杂脚本的利器。 |
记住这个黄金法则:当你需要处理函数的所有参数时,几乎总是应该使用 。 它能确保脚本的健壮性,尤其是在处理可能包含空格的文件名或路径时。
