在 Shell 脚本中获取命令行参数
在 Shell 脚本(如 Bash)中,命令行参数通过一些特殊的变量来访问,这是最常见和最直接的方式。

(图片来源网络,侵删)
基本参数变量
假设你有一个脚本 test.sh,执行 ./test.sh arg1 arg2 arg3:
| 变量 | 含义 | 示例 (./test.sh arg1 arg2 arg3) |
|---|---|---|
$0 |
脚本自身的名称 | ./test.sh |
$1 |
第一个参数 | arg1 |
$2 |
第二个参数 | arg2 |
$3 |
第三个参数 | arg3 |
| ... | ... | ... |
$9 |
第九个参数 | arg9 |
${10} |
第十个参数(注意:${10} 需要花括号) |
arg10 |
示例脚本 test.sh:
#!/bin/bash echo "脚本名称: $0" echo "第一个参数: $1" echo "第二个参数: $2" echo "第三个参数: $3"
执行结果:
chmod +x test.sh # 给脚本执行权限 ./test.sh hello world "this is a test"
输出:

(图片来源网络,侵删)
脚本名称: ./test.sh
第一个参数: hello
第二个参数: world
第三个参数: this is a test
特殊参数变量
除了单个参数,还有一些特殊的变量可以提供更丰富的信息。
| 变量 | 含义 |
|---|---|
| 传递给脚本的参数个数。 | |
| 将所有参数视为一个整体(用空格连接)。 | |
| 将所有参数视为多个独立的单词(通常用于循环)。 | |
| 当前脚本的进程ID (PID)。 | |
| 上一个命令的退出状态码(0 表示成功,非 0 表示失败)。 | |
| 当前 Shell 使用过的启动标志。 |
示例脚本 special_vars.sh:
#!/bin/bash echo "参数个数: $#" echo "所有参数作为一个字符串: $*" echo "所有参数作为独立单词: $@" # 使用 $@ 循环处理参数 echo "--- 使用 $@ 循环 ---" for arg in "$@"; do echo "参数: $arg" done # 使用 $* 循环处理参数 (注意引号的影响) echo "--- 使用 $* 循环 ---" for arg in "$*"; do echo "参数: $arg" done
执行结果:
./special_vars.sh a b c d
输出:

(图片来源网络,侵删)
参数个数: 4
所有参数作为一个字符串: a b c d
所有参数作为独立单词: a b c d
--- 使用 $@ 循环 ---
参数: a
参数: b
参数: c
参数: d
--- 使用 $* 循环 ---
参数: a b c d
关键区别: 会将所有参数合并成一个字符串,而 会保持每个参数的独立性,在 for 循环中, 是正确处理带空格参数的方式。
高级参数处理:getopts
当你的脚本需要处理类似 ./script.sh -f filename -v 这样的选项(flags)时,手动解析 $1, $2 会变得非常麻烦,这时,getopts 是最佳选择。
getopts 是 Shell 内置命令,用于解析位置参数中的选项。
语法:
getopts optstring name [arg...]
optstring: 定义了有效的选项字符,如果一个选项字符后面跟着冒号 ,表示该选项需要一个参数值。name: 一个变量名,getopts会将找到的选项字符存入这个变量。arg: 要解析的参数列表,默认是 。
工作原理:
getopts 会循环处理参数,每次找到一个选项:
- 将选项字符存入
name变量。 - 如果选项需要参数 (
optstring中带 ),参数值会存入OPTARG变量。 - 选项的索引存入
OPTIND变量。 - 当选项解析完毕或遇到无效选项时,
getopts返回非零值,循环结束。
示例脚本 getopts_example.sh:
#!/bin/bash
# 初始化变量
input_file=""
verbose=false
# 定义选项: f: 表示 -f 需要参数; v 表示 -v 不需要参数
while getopts "f:v" opt; do
case $opt in
f)
input_file="$OPTARG"
echo "找到文件选项: -f $OPTARG"
;;
v)
verbose=true
echo "找到详细选项: -v"
;;
\?)
echo "无效选项: -$OPTARG" >&2
exit 1
;;
:)
echo "选项 -$OPTARG 需要参数." >&2
exit 1
;;
esac
done
# 移除已处理的选项,剩下的就是位置参数
shift $((OPTIND - 1))
echo "------------------------------------"
echo "输入文件: ${input_file:-'未指定'}"
echo "详细模式: 开启"
echo "剩余位置参数: $@"
执行结果:
# 有效调用 ./getopts_example.sh -f mydata.txt -v arg1 arg2
输出:
找到文件选项: -f mydata.txt
找到详细选项: -v
------------------------------------
输入文件: mydata.txt
详细模式: 开启
剩余位置参数: arg1 arg2
# 无效调用 ./getopts_example.sh -f
输出:
选项 -f 需要参数.
在 C/C++ 程序中获取命令行参数
在 C/C++ 中,命令行参数通过 main 函数的两个参数传递。
main 函数的参数
int main(int argc, char *argv[]);
argc(argument count): 一个整数,表示argv数组中元素的个数,即传递给程序的参数总数。注意:argv[0]是程序自身的名称。argv(argument vector): 一个指向字符串数组的指针,每个字符串是一个命令行参数。
示例 C 程序 args.c:
#include <stdio.h>
int main(int argc, char *argv[]) {
// 打印参数总数 (包含程序名)
printf("参数总数 (argc): %d\n", argc);
// 循环打印每个参数
for (int i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
return 0;
}
编译和执行:
gcc args.c -o args ./args arg1 "arg with space" arg3
输出:
参数总数 (argc): 4
argv[0] = ./args
argv[1] = arg1
argv[2] = arg with space
argv[3] = arg3
C++ 版本
C++ 的版本几乎完全相同,只是语法略有不同。
示例 C++ 程序 args.cpp:
#include <iostream>
#include <vector>
#include <string>
int main(int argc, char* argv[]) {
std::cout << "参数总数 (argc): " << argc << std::endl;
// 使用范围 for 循环更现代
std::cout << "所有参数:" << std::endl;
for (int i = 0; i < argc; ++i) {
std::cout << "argv[" << i << "] = " << argv[i] << std::endl;
}
return 0;
}
编译和执行:
g++ args.cpp -o args_cpp ./args_cpp arg1 "arg with space" arg3
输出与 C 版本相同。
C++17 更简洁的写法
C++17 引入了 std::string_view 和 std::filesystem,让处理参数变得更方便和安全。
#include <iostream>
#include <string_view>
#include <vector>
int main(int argc, char* argv[]) {
// 将 char* 转换为 std::string_view,避免不必要的拷贝
std::vector<std::string_view> args(argv, argv + argc);
std::cout << "参数总数: " << args.size() << std::endl;
std::cout << "所有参数:" << std::endl;
for (const auto& arg : args) {
std::cout << "- " << arg << std::endl;
}
return 0;
}
| 环境 | 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| Shell 脚本 | $1, $2, ... |
简单的、按顺序的参数 | 简单直接,无需额外工具 | 参数多时难以管理,无法处理选项 |
| Shell 脚本 | , , | 获取参数总数或所有参数 | 提供元信息,方便循环 | getopts 更适合复杂选项 |
| Shell 脚本 | getopts |
解析 -f, -v 等选项 |
功能强大,能处理带参数的选项,能检测错误 | 语法稍复杂,需要 case 语句 |
| C/C++ | main(int argc, char *argv[]) |
编译型程序 | 灵活、强大、性能高 | 需要编译,比 Shell 脚本复杂 |
- 对于简单的自动化任务和快速原型,Shell 脚本 +
$1,$2或getopts是首选。 - 对于需要高性能、复杂逻辑或与系统底层交互的程序,C/C++ 是不二之选。
