省流:
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' ] ; thenwhile getopts ":a:b:c:h" optdocase $opt ina)....;;?)echo '未知參數';exit 1;;;esacdoneexit 0;
fi## 如果是 doline -a 123 -b 123 -c 123 就執行下面的代碼
while getopts ":a:b:c:h" opt
docase $opt ina)....;;?)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' ] ; thenshift; # 重讀取過的$1之后開始判斷命令while getopts ":a:b:c:h" optdocase $opt ina)....;;?)echo '未知參數';exit 1;;;esacdoneexit 0;
fi## 如果是 doline -a 123 -b 123 -c 123 就執行下面的代碼
while getopts ":a:b:c:h" opt
docase $opt ina)....;;?)echo '未知參數';exit 1;;;esac
done
以上代碼在判斷第一個參數是
init
之后,會立刻進行shift
,后面的內容就會一一對應起來了。
簡單驗證
寫個簡單的腳本,驗證一下:
#!/bin/bashif [ $1 = 'init' ] ; then echo $* ;exit 0;
fiif [ $1 = 'run' ] ; thenshift; ## SHIFT 在這里echo $*;exit 0;
fi
期望輸出:
執行./testShift init -a -b -c
輸出init -a -b -c
執行./testShift run -a -b -c
輸出-a -b -c
驗證成功!!
參考
Tomcat 啟動腳本