shell参数传递

背景

在脚本,或者shell的function中,常常会有参数的出现,甚至有时会需要选项卡

特殊变量

变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。
$? 上个命令的退出状态,或函数的返回值。
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
“$@” 参数列表的数组
“$*” 参数列表的集合,为一个字符串

后者示例

1
2
3
4
5
6
7
8
9
#! test.sh
for arg in "$*"
do
echo $arg
done
for arg in "$@"
do
echo $arg
done

执行

1
./test.sh one two three

输出为

1
2
3
4
one two three        #"$*"的
one #"$@"的
two
three

选项卡

前言

在参数仅有一个不需要分类时,使用带一个参数的方式就好,不需要使用选项卡

1
./test.sh 10

好过只有一种选项的

1
./test.sh -n 10

选项的说明

1
2
3
4
5
6
-a -b               #短选项
-ab #短选项可以放在一起
-a arg1 #短选项带参数
-a1 #短选项带可选参数
--b-long #长选项
--c-long arg1 #长选项带参数

选项的获取

分两种

  • 独立的=getopts=,不支持长选项和可选参数,但是非常简单
  • bash自带的=getopt=,支持长选项和可选参数,zsh兼容bash,应该也能用
  1. getopts

    从参数字符串中 提取 $opt 变量与 $OPTARG 变量,
    然后 逐个 使用 case 语句(类似C语言的which语句)进行处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #! .bashrc
    function apple(){
    while getopts "z:xc" opt #冒号表示z需要有参数
    do
    case $opt in
    z)
    echo "z's arg:$OPTARG";;   #case后面的双分号不能少
    x)
    echo "x's choosen";;
    c)
    echo "c's choosen";;
    ?)
    echo "bad options";;
    esac
    done
    }

    结果为

    1
    2
    3
    4
    5
    6
    > apple -z 1 -xcy
    z's arg:1
    x's choosen
    c's choosen
    apple:1: bad option: -y #系统的提示
    bad options         #自定义的提示
  2. getopt

    实际上就是将短参数分开整理的功能
    例如将 -abc 转换成 -a -b -c
    没有特定的 $OPTARG 变量
    所以常搭配 循环shift 语句,将选项卡逐个放在 $1,这时参数看情况放在 $2 或者没有等
    总思路就是 将选项卡视为参数 ,然后使用case语句进行处理

    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
    31
    32
    33
    34
    # echo $1
    temp=`getopt -o ab:c:: --long along,blong: -- "$@"`
    echo $temp
    set -- $temp
    echo
    while [ -n "$1" ]
    do
    echo "\$1 is $1"
    case $1 in
    -a|--along)
    echo "a's choosen";shift;;
    -b|--blong)
    echo "b's arg:$2";shift 2;;
    -c)
    case $2 in
    "")
    echo "c's choosen";;
    *)
    echo "c's arg:$2";;
    esac;
    shift 2;;
    --)
    shift;
    break;;
    esac
    done
    echo "remaining args"
    for arg do
    echo '-->'"$arg";
    done
    # for arg in $@
    # do
    # echo '-->'"$arg"
    # done
    • -o表示短选项,-long表示长选项,-n表示错误,–表示后接正常参数
    • 长选项之间用逗号分割
    • 一个冒号表示有参数,两个冒号表示有可选参数,长选项没有可选参数
      • 可选参数与选项卡没有间隔,如果长选项的可选参数是字符,
        那么将不好界定是输入了一个参数还是输入了一个非法的长选项
    • getopt 将参数表的字符串进行加工
    • set -- 将加工好的字符串重新设为参数表
    • 参数表在这里以空格为划分,故 'a b' 不被认为是一个,而分别是 'ab'
    • for arg do 这个命令的格式最好不要学

    使用

    1
    ./me.sh -ac2 -b 1 --along --blong 3 'a b'

    结果为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    -a -c '2' -b '1' --along --blong '3' -- 'a b'
    $1 is -a
    a's choosen
    $1 is -c
    c's arg:'2'
    $1 is -b
    b's arg:'1'
    $1 is --along
    a's choosen
    $1 is --blong
    b's arg:'3'
    $1 is --
    remaining args
    -->'a
    -->b'

    可见 getopt
    -ac2 -b 1 --along --blong 3 'a b' 处理为
    -a -c '2' -b '1' --along --blong '3' -- 'a b'

    ac2 -b 1 --along --blong 3 'a b' 将会被处理为
    -a -c '' -b '1' --along --blong '3' -- 'a b'
    即可选参数后将会有空字符出现,所以对可选参数的处理中又使用了一层case

  3. 使用注意

    两者都不会自带面对同样含义选项卡时只执行一次的功能,
    比如 -h--help 这里会执行两次
    不知道别人怎么解决的