在 getopts 之後解析腳本參數
我有一個腳本,我在其中使用getopts實現了開關。但是,我無法引用下一個論點。
我的腳本用於在本地開發環境中反向移植我們網站的備份。我添加了一個
-p
開關來執行一些部署後步驟。這是我的語法:backport -p /path/to/website_backup.sql.gz
因此,在切換之前,我正在測試是否指定了一個文件,並且它是一個正確的文件。由於文件名路徑是唯一的參數,我可以假設它是必要的,而且它也是第一個參數 (
$1
)。if [[ $# -eq 0 ]] ; then echo 'Specifcy the sql file to backport.'; exit 0; fi if [[ ! -f "$1" ]]; then echo "$1 is not a valid file."; exit 0; fi
我找到了這個答案,它展示瞭如何使用 getopts 解析開關參數的範例:
while getopts "p" opt; do case $opt in p) p_post_deploy=true ;; # Handle -a esac done
當然,使用
$1
as 參數在實現 getopts 後不起作用。沒有開關就好了。但是,當我添加開關時,它當然是第一個參數,我的腳本正在測試它是否是一個文件。$ backport -p /path/to/website_backup.sql.gz -p is not a valid file.
因此,隨著開關的引入,我不能依賴出現在命令中特定位置的任何參數。硬編碼
$2
不起作用,因為如果沒有開關,文件名參數將不是第二個參數。我想要一個解決方案,它允許我在切換後接受參數,並允許我在未來引入新的開關,同時只更新程式碼以自己處理新的開關(並且不必重新洗牌以後可能會移動的參數引入新開關)。我查看了 unix.stackexchange 問題的答案,該問題指示我如何使用 getopts 解析開關。提到的答案
$*
之一是表示剩餘參數的變數。if [[ "$*" -eq 0 ]] ; then echo 'Specifcy the sql file to backport.'; exit 0; fi
但是,當我嘗試使用它時,我沒有正確表達語法,並且出現解析錯誤。
~/scripts/backport: line 14: [[: /d/Downloads/database.sql.gz: syntax error: operand expected (error token is "/d/Downloads/database.sql.gz")
如何在 getops 之後測試文件名參數?
這是目前版本的腳本:
$ cat backport #!/bin/bash set -e while getopts "p" opt; do case $opt in p) p_post_deploy=true ;; esac done shift $(($OPTIND - 1)) # testing what this variable looks like printf "Remaining arguments are: %s\n" "$*" if [[ "$*" -eq 0 ]] ; then echo 'Specifcy the sql file to backport.'; exit 0; fi if [[ ! -f "$*" ]]; then echo "$* is not a valid file."; exit 0; fi drush @local.dev sql-drop -y ; zcat $1 | drush @local.dev sqlc ; drush @local.dev cr; if [ ! -z "$p_post_deploy" ] ; then echo "Running post-deploy..." SCRIPT_PATH=$(dirname "$BASH_SOURCE") source "$SCRIPT_PATH/post-deploy" post_deploy fi
我只能責怪自己溝通不暢,但 Kusalananda 在評論中給出了我一直在尋找的答案。
使用
getopts
後解析開關while getopts "p" opt; do case $opt in p) p_post_deploy=true ;; esac done
這條線
shift "$((OPTIND - 1))"
將從參數列表中刪除所有開關,以便您可以再次使用位置參數,就像沒有開關一樣。
外殼不會
OPTIND
自動重置。您必須手動重置它。
您對測試構造的應用
if [[ "$*" -eq 0 ]]
是不正確的。
-eq
用於整數比較,並且鑑於它$*
指的是所有剩餘參數的參數列表,而不是它們的數量,您的測試構造必然會產生語法錯誤,除非該點的剩餘參數列表恰好包含一個元素,還必須碰巧代表一個整數(這不是您想要實現的)。現在,對於實際任務,我認為只要你允許任意順序(即只要你不
-<some letter>
指定文件名必須放在最後)。如果你想使用getopts
,你可能只是想讓文件名也成為一個選項參數,要求它被指定為-f <filename>
. 然後你可以使用while getopts "pf:" opt; do case $opt in p) p_post_deploy=true ;; f) backportfile=$OPTARG ;; esac done
getopts
如果未指定文件名,則會自動抱怨。./test.sh: option requires an argument -- f
如果文件存在,您仍然可以稍後進行測試,如
if [[ ! -f "$backportfile" ]] then echo "$backportfile is not a valid file" exit 1 fi