省流:
shift
关键字
探索思路
最近有一个小小的需求,写一个类似于docker run -a -b -c
这样的脚本,这个脚本名为doline
,它本身可以执行(doline -a -b -c
),同时又带有几个如run、init、start
这样的参数,感觉有点说不明白,以下是几种场景:
doline -a -b -c # 直接传参使用
doline -h # 查看帮助文档
doline init -a -b -c # 初始化一些参数,再次执行时可以不带初始化的参数
doline init -h # 查看关于'init'的帮助文档
doline run -a -b -c # ....
有多个类似于init、run
这样的二级命令,我之前在【Shell 脚本传递参数的两种方式:位置传参与指令式传参】中详细介绍了Shell的两种传参方式,因此我基于这两种方式开始探索,并有了初步的想法(实操之后发现并不可以)。
首先使用最简单的位置传参,判断$1
的值是不是init、run
这样的参数,如果不是的话直接getopts
如果是的话就在init
下面再进行一次getopts
,并且在init
的结尾进行exit
。
伪代码大概如下:
## 如果是 doline init -a 123 -b 123 -c 123 就执行下面的代码
if [ $1 = 'init' ] ; then
while getopts ":a:b:c:h" opt
do
case $opt in
a)
....
;;
?)
echo '未知参数';
exit 1;
;;
esac
done
exit 0;
fi
## 如果是 doline -a 123 -b 123 -c 123 就执行下面的代码
while getopts ":a:b:c:h" opt
do
case $opt in
a)
....
;;
?)
echo '未知参数';
exit 1;
;;
esac
done
但是,实操之后失败了,如果是直接doline -a -b -c
是可以的,但是doline init
的话就全部执行失败,我在代码起始的位置输出所有的参数echo $*
,参数是init -a -b -c
,这样的话init
也占了一个位置,后面的所有参数都对不上位置了,显然是不行的,但是逻辑上是可以的。
成功案例
这时候就要想办法,比如是否有其他的参数获取方式?或者如何在判断是init
之后给init
这个参数删除掉呢?经过一番查找,找到了一个十分关键的关键词shift
切换。
shift
的原理:
如果你输入的参数是init -a -b -c
,在读取init
之后进行shift,参数列表就变为-a -b -c
,这个时候就能对应上了。
这个时候只需要对上面的内容稍加改在,在判断第一个参数是init
之后,立刻进行shift就可以了,更改后的脚本如下:
if [ $1 = 'init' ] ; then
shift; # 重读取过的$1之后开始判断命令
while getopts ":a:b:c:h" opt
do
case $opt in
a)
....
;;
?)
echo '未知参数';
exit 1;
;;
esac
done
exit 0;
fi
## 如果是 doline -a 123 -b 123 -c 123 就执行下面的代码
while getopts ":a:b:c:h" opt
do
case $opt in
a)
....
;;
?)
echo '未知参数';
exit 1;
;;
esac
done
以上代码在判断第一个参数是
init
之后,会立刻进行shift
,后面的内容就会一一对应起来了。
简单验证
写个简单的脚本,验证一下:
#!/bin/bash
if [ $1 = 'init' ] ; then
echo $* ;
exit 0;
fi
if [ $1 = 'run' ] ; then
shift; ## SHIFT 在这里
echo $*;
exit 0;
fi
期望输出:
执行./testShift init -a -b -c
输出init -a -b -c
执行./testShift run -a -b -c
输出-a -b -c
验证成功!!
参考
Tomcat 启动脚本