Bash 脚本的参数是向脚本传递输入的核心机制,通过特殊变量和解析工具实现灵活控制。以下从参数类型、访问方式、解析技术到最佳实践进行系统介绍:


⚙️ 一、参数类型与访问方式

  1. 位置参数

    • 定义:按顺序传递的参数,通过 $1$2...$n 访问。
    • 示例
      ./script.sh arg1 arg2  # $1="arg1", $2="arg2"
      
    • 特殊变量
      • $0:脚本自身名称(如 ./script.sh
      • $#:参数总数(如 2
      • $@:所有参数的独立列表(推荐用 "$@" 保留空格分隔的参数完整性)
      • $*:所有参数合并为单个字符串(用空格连接)

    $@$* 的区别
    | 场景 | "$@" | "$*" |
    |----------------|----------------------------|----------------------------|
    | 参数带空格 | 保留独立性(如 "arg 1") | 合并为 "arg 1 arg2" |
    | 循环遍历 | 每个参数单独处理 | 整体作为单个字符串处理 |

  2. 选项参数

    • 短选项:以单连字符开头(如 -v-f file.txt
    • 长选项:以双连字符开头(如 --verbose--file=file.txt
    • 标志参数:布尔型选项(如 -h 显示帮助)

🔍 二、参数解析技术

1. 直接访问位置参数

适用场景:参数数量固定且顺序明确。

echo "第一个参数: $1"
echo "第二个参数: $2"

2. 循环遍历参数

  • for 循环 + $@(推荐处理带空格的参数):
    for arg in "$@"; do
        echo "参数: $arg"
    done
    
  • shift 命令:左移参数,逐项处理(适合不定数量参数):
    while [ "$#" -gt 0 ]; do
        echo "当前参数: $1"
        shift  # 丢弃$1,$2变为$1
    done
    

3. 解析选项参数:getopts

功能:标准化解析带值的选项(如 -a value)。

while getopts ":a:b:" opt; do
    case $opt in
        a) echo "选项a的值: $OPTARG" ;;  # $OPTARG 获取选项值
        b) echo "选项b的值: $OPTARG" ;;
        ?) echo "无效选项: -$OPTARG" ;;
    esac
done

说明

  • : 表示选项需参数(如 -a value
  • 解析后使用 shift $((OPTIND-1)) 跳过已处理选项

4. 复杂选项解析:getopt

适用场景:支持长选项(如 --file)和可选参数:

TEMP=$(getopt -o a:b:c --long file:,help -n "脚本名" -- "$@")
eval set -- "$TEMP"  # 重组参数
while true; do
    case "$1" in
        --file) file="$2"; shift 2 ;;
        --help) show_help; exit 0 ;;
        --) shift; break ;;
    esac
done

🛠️ 三、实用技巧与最佳实践

  1. 参数验证

    • 检查数量:避免缺少参数导致错误:
      if [ $# -lt 2 ]; then
          echo "需提供至少2个参数!"
          exit 1
      fi
      
    • 空参数处理-z "$1" 检测空参数
  2. 默认值与帮助信息

    name="默认名"  # 设置默认值
    usage() { echo "用法: $0 [-n 名称]"; exit 1; }
    while getopts ":n:" opt; do
        case $opt in n) name="$OPTARG" ;; ?) usage ;; esac
    done
    
  3. 封装脚本的参数传递
    封装脚本需转发所有参数(如 egrep 封装 grep -E):

    #!/bin/sh
    exec grep -E "$@"
    
  4. 安全提示

    • 验证用户输入的参数(如检查文件是否存在 [ -f "$1" ]
    • 避免直接执行未过滤的参数(防命令注入)

💻 四、综合示例

#!/bin/bash
# 解析选项和位置参数
while getopts ":v" opt; do
    case $opt in v) verbose=1 ;; esac
done
shift $((OPTIND-1))

# 验证位置参数
if [ $# -eq 0 ]; then
    echo "错误:需提供文件名!" >&2
    exit 1
fi

# 处理文件
for file in "$@"; do
    [ "$verbose" ] && echo "处理文件: $file"
    wc -l "$file"
done

执行

./count_lines.sh -v file1.txt "file 2.txt"

总结

  • 基础访问:位置参数($1, $#, $@)是核心;
  • 进阶解析getopts 处理短选项,getopt 支持长选项;
  • 健壮性:验证参数、设置默认值、生成帮助信息;
  • 场景适配:简单脚本用位置参数,复杂逻辑用选项解析。