对于许多脚本都希望有多个参数的输入,对于shell
这种脚本更是不例外,一般程序的起始函数(main
)都会有一个args选项代表着输入的参数项,那么解析这些参数项目就是主要的问题,这里有两种解析方法解析脚本输入的参数:
getopt
)配合shift
进行格式化解析(不一定所有系统都,需要检测一下)在shell脚本中,命令$
后加一些特殊的标记可以取脚本的传入参数,如$0
取脚本输入的第一个参数,$1
取第二个参数等:
参数 | 描述 |
---|---|
$0 | 命令本身,类似c的argv[0] |
$1、$2 …… | 第1个参数、第2个参数…… |
$# | 参数的个数,不包括$0 |
$@ | 以列表的形式返回参数列表,不包括$0 |
$? | 最后运行的命令结束代码 |
在shell中$1
到$9
相当于一个双向队列,脚本的参数按顺序排入1~9这些变量中,若脚本参数多于9个,就需要通过shift函数,让第一个参数出队,队列中顺序左移,第10个参数入队到$9
中,因此shift
可以处理脚本超过10个参数的情况,但更多的是用来解析脚本多参数
shift
可以把参数列表左移1个,同时参数个数会减少1,shift 2
可以把参数列表左移2个,同时参数个数会减少2
但有个情况:若只有2个参数,运行shift 3 函数会运行出错返回1,可以通过 $? 检查是否执行成功xxx.sh:
shift 3;
echo "$?"
echo "$#"123
执行
xxx.sh -1 -21
输出
1
2
可以看到,shift
并没有执行,返回1,参数并没有移动。
因此,在处理脚本参数的时候,必要情况需要判断shift
是否成功。当然getopt
函数可以很大程度的避免这些判断逻辑。
这里主要运用$#
和$@
这两个变量即可遍历所有的传入参数,在不使用getopt
这个函数的情况下,要遍历所有的输入参数可以参考如下脚本:
until [ $# -eq 0 ]
do
case "$1" in
-h|--help) echo "-h or --help";
exit 0;;
-a|--along) echo "-a or --along";shift;echo "after shift $#";;
-b|--blong) echo "-b or --blong";
case "$2" in
bval1) echo " b value 1";shift 2;echo "after shift $#";;
bval2) echo " b value 2";shift 2;echo "after shift $#";;
bval3) echo " b value 3";shift 2;echo "after shift $#";;
bval4) echo " b value 4";shift 2;echo "after shift $#";;
#不能判断-b后面是否会有别的参数,因此不能直接shift 2
*) shift; echo " unknow b value";
if [ $# -eq 0 ];then
exit 0;
fi
shift;;
esac;;
-c|--clong) echo "-c or --clong";
case "$2" in
cval1) echo " c value 1";shift 2;;
cval2) echo " c value 2";shift 2;;
cval3) echo " c value 3";shift 2;;
cval4) echo " c value 4";shift 2;;
*) shift; echo " unknow c value";
if [ $# -eq 0 ];then
exit 0;
fi
shift;;
esac;;
*) echo " unknow prop $1";shift;;
esac
done
上面,在case 判断-b 后面的值时,再不确定-b后面一定有值,不能直接shift 2
而是需要先进行一次判读
但按照Linus的风格,对于一多个单一属性可以连起来写,如对于xxx.sh -a -b -c
可以写成xxx.sh -abc
若按照上面这种写法,要处理还得写好几个case,因此轮到重要的一个函数getopt
登场
getopt
辅助参数的解析getopt
不是标准的unix命令,但它在大多数的发行版中都会带有,getopt
虽然是带个get但此函数其实主要不是获取而是规范
getopt
后面接受-o
选项表示程序可接受的短选项 如-o ab:c::
,表示程序参数后面可接受的选项为-a -b -c 其中-a后面不接受参数,-b后面必须接受参数(,-c后面参数可选(:
getopt
后面接受--long
选项表示程序可接受的短选项 如--long along,blong:,clong::
,长选项用逗号分隔开,后面接参数的标记号和短选项一致
getopt
后面 -n
选项为解析错误时提示的脚本名字
在对参数进行解析前先通过getopt进行解析
ARGS=`getopt -o ab:c: --long along,blong:,clong: -- "$@"`
#判断是否执行成功,没执行成功退出
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
#重新设置参数
eval set -- "$ARGS"12345
通过getopt
重新解析过的参数会更好解析,如对-a -b -c
合起来写成-abc
也可以解析,如下面xxx.sh
ARGS=`getopt -o abc -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
eval set -- "$ARGS"
while true;do
case "$1" in
-a)
echo "a"
shift;;
-b)
echo "b"
shift;;
-c)
echo "c"
shift;;
--)
echo "--"
shift
break
;;
*)
echo "??"
shift
;;
esac
done
执行:
xxx.sh -abc1
输出:
a
b
c
--
输入xxx.sh -cab
或xxx.sh -bac
都可以,若不使用getopt就需要借助正则来判断这种多样化的组合了
使用getopt
还有个好处,可以检测一些异常输入,如上例子输入xxx.sh -g
会输出:
getopt:无效选项 -- g1
__version__=1.0.2
echo "pull logs version $__version__"
if [ -z "$1" ]
then
echo "pull all"
exit
fi
param_info="Please pass in the correct parameter: \n
-1 -- /userdata/logs/ \n
-2 -- /userdata/upload/pending/ \n
-3 -- /userdata/core_dump_files/ \n
-4 -- /userdata/bags \n
default -- All of the above "
#-o表示短选项,两个冒号表示该选项有一个可选参数,可选参数必须紧贴选项
#如-carg 而不能是-c arg
#--long表示长选项
#"$@"在上面解释过
# -n:出错时的信息
# -- :举一个例子比较好理解:
#我们要创建一个名字为 "-f"的目录你会怎么办?
# mkdir -f #不成功,因为-f会被mkdir当作选项来解析,这时就可以使用
# mkdir -- -f 这样-f就不会被作为选项。
# 经过getopt解析后的参数会自动插入 -- 来分隔参数列表以外的参数,所以这条命令以后的参数会多一个 --
ARGS=`getopt -o 1234 -- "$@"`
if [ $? != 0 ] ; then echo -e $param_info >&2 ; exit 1 ; fi
# 重新设置参数,这里的set -- 指令用于更新位置参数,即用--后面的参数替代原有的参数
eval set -- "$ARGS"
# 显示所有参数
echo "$@"
# 显示重新解析后的参数
echo "ARGS: $ARGS"
flag=0
while true;do
case "$1" in
-1)
echo "pull /userdata/logs/"
flag=1
shift
;;
-2)
echo "pull /userdata/upload/pending/"
flag=1
shift
;;
-3)
echo "pull /userdata/core_dump_files/"
flag=1
shift
;;
-4)
echo "pull /userdata/bags/"
flag=1
shift
;;
--)
echo "--"
if [ $flag -eq 0 ]
then
echo -e $param_info
exit
fi
shift
break
;;
esac
done
执行
./test.sh -13
输出结果:
pull logs version 1.0.2
-1 -3 --
ARGS: -1 -3 --
pull /userdata/logs/
pull /userdata/core_dump_files/
--
fun_do_a_property()
{
echo "a($1)"
}
fun_do_b_property()
{
echo "b($1)"
}
ARGS=`getopt -o hva:b: --long help,version,along:,blong: -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
eval set -- "$ARGS"
while true;do
case "$1" in
-a|--along)
echo "-a | --along"
fun_do_a_property $2
shift 2
;;
-b|--blong)
echo "-b | --blong"
fun_do_b_property $2
shift 2
;;
-v|--version)
echo "-v | --version"
shift
;;
-h|--help)
echo "-h | --help"
shift
;;
--)
shift
break
;;
*)
echo "未知的属性:{$1}"
exit 1
;;
esac
done
执行example.sh -a 123 -b 456
-a | --along
a(123)
-b | --blong
b(456)
·
·
·
欢迎各位老铁一键三连,本号后续会不断更新树莓派、人工智能、STM32、ROS小车相关文章和知识。
大家对感兴趣的知识点可以在文章下面留言,我可以优先帮大家讲解哦
欢迎大家光临我的淘宝小店【玩转智能机器人】,会定期推出教程中使用的物美价优的硬件,你的光临就是对我的支持
原创不易,转载请说明出处。