首页 Shell 参数解析
文章
取消

Shell 参数解析

一般的 shell 脚本都不会有太复杂的命令行参数,这时候使用$n获取位置参数就足够了。

但是,有些时候需要解析一些比较复杂的命令行参数,这时候就需要 shift 和 getopts 了。

shift

shift是 shell 的一个内建命令,常用于位置参数的解析;

shift 将所有位置参数(除$0)往前移动一个单位,即丢弃最前边的参数;

如:shift 3,往前移动三个位置、不带参数的shift则相当于shift 1

最简单的用法,依次获取每个位置参数(当然,这只是演示一下 shift 的用法)

1
2
3
4
5
6
7
8
#!/bin/bash

echo "文件名: $0"

while [ $# -gt 0 ]; do
    echo "参数$((++i)): $1"
    shift
done
1
2
3
4
5
6
$ ./test.sh a b c d
文件名: ./test.sh
参数1: a
参数2: b
参数3: c
参数4: d

getopts

除了使用 shift,我们还可以使用 getopts 内建命令,它主要是模仿 C 库中的 getopt() 函数。

语法:getopts optstring optname [arguments ...]

变量$OPTIND:选项所在的索引值,初始值为 1,它会自动递增;

变量$OPTARG:选项所附带的参数(如果有的话)。

optstring 是选项字符串,用来定义如何处理选项;

optname 是一个变量,用来存储捕获到的选项;

如果没有 arguments,则从当前的位置参数解析;

如果有 arguments,则从给定的 arguments 解析。


optstring格式:

  • 如果选项后面没有:号,说明该选项后没有参数值;
  • 如果选项后面带有:号,说明该选项后需要提供参数,参数值存储在$OPTARG

当 getopts 遇到未知选项选项缺少参数的情况时:

  • 如果 optstring 以:开头,getopts 将不会输出默认的出错信息,而是交给我们自己来处理。并且,遇到未知选项时将optname设为?,遇到缺少参数时将optname设为:
  • 如果 optstring 不以:开头,getopts 将输出默认的出错信息,并且不区分未知选项和缺少参数的情况,统一将optname设为?

简单例子,演示了如何使用 getopts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

if [ $# -eq 0 ]; then
    echo "Usage ..." 1>&2   # 用法介绍
    exit 1
fi

while getopts ":s:p:m:k:b:l:uvh" OPT; do
    case $OPT in
        s) server_ip=$OPTARG;;
        p) server_port=$OPTARG;;
        m) method=$OPTARG;;
        k) passwd=$OPTARG;;
        b) bind_ip=$OPTARG;;
        l) listen_port=$OPTARG;;
        u) udp_relay=1;;
        v) verbose=1;;
        h) help=1;;
        :)  # 缺少参数
            echo "missing argument to '-$OPTARG'" 1>&2
            exit 1
            ;;
        \?) # 未知选项
            echo "unknown option '-$OPTARG'" 1>&2
            exit 1
            ;;
    esac
done

# 程序主逻辑 ...
1
2
3
4
5
6
7
8
9
10
$ ./test.sh -s
missing argument to '-s'

$ ./test.sh
Usage ...

$ ./test.sh -y
unknown option '-y'

$ ./test.sh -s server -p 5555 -m rc4-md5 -k password -b 0.0.0.0 -l 1080 -u -v

在函数中使用 getopts

因为$OPTIND每次都会自增,因此调用一次函数后,$OPTIND就不再是 1 了,再调用函数就会无法解析;

为了解决这个问题,可以在函数中定义一个与$OPTIND同名的 local 变量,并且初始值设为 1,就可以了。

本文由作者按照 CC BY 4.0 进行授权

Shell 特殊命令

Shell 别名扩展