bash 参数传递与获取

写脚本的时候,难免需要传递参数,这时需要知道在shell中如何获取参数并且解析

基础用法

echo $n    # 按照顺序传递的第几个参数,从0开始索引,脚本自己也作为一个参数传递,所以$0就是脚本自己
echo $#    # 参数个数,不包括脚本自己
echo $*    # 所有参数,是一个字符串
echo $@    # 所有参数,是一个数组
bash test.sh -a b --c=d
$0 test.sh
$1 -a
$2 b
$3 --c=d
$# 3
$*/$@ -a b --c=d

getopts

上面的方法,函数少的时候,可以应付;函数多的话就比较麻烦了,这时候可以使用getopts实现

#!/bin/bash
while getopts 'a:b:c:d' opts; do
        case $opts in
                a) echo $OPTARG;;
                b) echo $OPTARG;;
                ?) echo 'aaa';;
        esac
done

上面就是通过getopts从脚本参数中获取a b c d开头指定的参数,如果传递了没有指定的参数会报错,?就是捕获这种参数。OPTARG是指定参数所赋的值,会保存在这个里面

bash test.sh -a abc -f a
abc
test.sh:非法选项 -- f
aaa

shift

shift会把参数序号减一,也方便我们自己解析

#!/bin/bash
until [ -z "$1" ]
do
        case "$1" in
                -a)
                        echo "$2"
                        shift;;
                -b)
                        echo "$2"
                        shift;;
                -c)
                        echo "$2"
                        shift;;
                *)
                        echo "xxx"
                        exit 0
        esac
        shift
done

case的*是匹配所有,util是直到条件不满足就终止循环,-z就是判断参数是否是zero,也就是空

bash test.sh -a abc -b bbb -f ccc
abc
bbb
xxx

getopt

https://www.tutorialspoint.com/unix_commands/getopt.htm
使用getopts无法解析--的参数,getopt功能更强大,可以支持--,看一下官方的示例

#!/bin/bash

# read the options
# -o 指定短选项参数有哪些,参数后面不加冒号,就表示这个参数没有值;参数后面有一个冒号,就表示这个参数必须有一个值,格式随意-fMyfile.txt -f Myfile.txt -f=Myfile.txt都可以,实际上-fMyfile.txt和-f=Myfile.txt情形一样,-f并不在意=,只是把它作为参数的值,-f=Myfile.txt的值就是=Myfile.txt;参数后面有两个冒号,表示可以有一个值,值必须紧贴参数,也可以不写值,-s -sSource.txt都对
# --long 就是两个短横线的长参数
TEMP=`getopt -o f:s::d:a:: --long file-name:,source::,destination:,action:: -- "$@"`

# 这一句正常加上就可以,排序,把没有值的参数放后面
eval set -- "$TEMP"

# extract options and their arguments into variables.
# 遍历获取参数和其值
while true ; do
    case "$1" in
        -f|--file-name)
            fileName=$2 ; shift 2 ;;
        -s|--source)
            case "$2" in
                "") sourceDir='.' ; shift 2 ;;
                 *) sourceDir=$2 ; shift 2 ;;
            esac ;;
        -d|--destination)
            destinationDir=$2 ; shift 2;;
        -a|--action)
            case "$2" in
                "copy"|"move") action=$2 ; shift 2 ;;
                            *) action="copy" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done

# Now take action
echo "$action file $fileName from $sourceDir to $destinationDir"
bash test.sh -f MyFile.txt -s/home -d /home/test -aMove
Move file MyFile.txt from /home to /home/test

bash test.sh --file-name MyFile.txt --source=/home --dest /home/test --act=Move
Move file MyFile.txt from /home to /home/test

bash test.sh --file-name MyFile.txt --source=/home --dest /home/test --act
Copy file MyFile.txt from /home to /home/test

bash test.sh --file-name MyFile.txt --source=/home -a Move -d
getopt: option requires an argument -- d
Copy file MyFile.txt from /home to

这个的写法是固定的一套,你可以拷贝过去改改就可以用。

注意
每次shift会向后移一位,也就相当于把参数列表的第一位$1丢掉,那么$2就变成了$1.
在遍历的时候一定要注意,如果是参数有值,那么需要再跳一位,因为这一次把$1和$2都用掉了,下一次应该从$3开始;如果参数没值,不要跳多了,导致下一个参数被跳过

只获取长参数

如果想只获取长参数,需要这样写getopt -o "" --long file-name:,source::,destination:,action:: -- "$@",必须有-o,如果没有,会导致getopt无法解析第一个参数,不知道是--long

posted @ 2022-10-20 13:58  秋来叶黄  阅读(922)  评论(0编辑  收藏  举报