参数与 flag
程序收到的永远是一个字符串数组,选项和路径怎么解释,全靠约定。
argv
bash
ls -l folder/
# 程序收到 ["ls", "-l", "folder/"]| 概念 | 说明 |
|---|---|
argv[0] | 程序名 |
argv[1..] | 参数列表 |
| 类型 | 全是字符串,没有数字或布尔 |
| 解释权 | 在程序,不在 Shell |
选项约定
| 规则 | 例子 |
|---|---|
| 短选项 | -a |
| 长选项 | --all |
| 两者等价 | ls -a = ls --all |
| 短选项合并 | -la = -l -a |
| 顺序无关 | -la = -al |
| 可变文件参数 | rm a b c |
| 通用选项 | --help、--version、--verbose |
bash
touch -- -myfile
rm -- -myfile-- 之后不再解析选项,所有减号开头的字符串都当位置参数。
脚本里的位置参数
| 变量 | 含义 |
|---|---|
$0 | 脚本名 |
$1…$9 | 前九个参数 |
$# | 参数个数 |
$@ | 全部参数 |
"$@" | 每个参数独立 |
不加引号的 $@ 会重新切词,遍历参数几乎总是写 "$@"。
手动解析
bash
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose) verbose=1; shift ;;
--) shift; break ;;
*) files+=("$1"); shift ;;
esac
done复杂参数不要手写:Python 用 argparse,Go 用 flag,Rust 用 clap。
glob 在启动前展开
rm *.py 里,rm 收到的是展开后的文件名,不是 *.py。所以程序无法区分参数是手写的还是 Shell 展开的,带空格的参数必须用引号一路带到程序。
环境变量是另一条通道:不占 argv,子进程默认继承,适合配置而不是数据。