我撰寫了一個 bash 腳本來在我的服務器中自動安裝燈,它們運行良好,但在可讀性方面存在問題。
# Asking if want to install PHP or build from source
read -p "This script will install PHP, do you want to install it (y/n)?" phpchoice
case "$phpchoice" in
[Yy]* ) isinstallphp=yes;;
[Nn]* ) isinstallphp=no;;
* ) echo "invalid";;
esac
if [ isinstallphp == "yes" ]; then
# Prompt for php version
options=("php5.6" "php7.0" "php7.1" "php7.2" "php7.3" "php7.4" "php8.0" "php8.1")
function do_something () {
echo -e "${Ye}You picked ${Wh}$php_opt${Ye}, will be installing that instead${Nc}"
}
select php_opt in "${options[@]}"; do
case "$php_opt,$REPLY" in
php5.6,*|*,php5.6) do_something; break ;;
php7.0,*|*,php7.0) do_something; break ;;
php7.1,*|*,php7.1) do_something; break ;;
php7.2,*|*,php7.2) do_something; break ;;
php7.3,*|*,php7.3) do_something; break ;;
php7.4,*|*,php7.4) do_something; break ;;
php8.0,*|*,php8.0) do_something; break ;;
php8.1,*|*,php8.1) do_something; break ;;
esac
done
fi
我放置do_something函式的 case 陳述句部分看起來很亂,所有函式所做的就是用顏色回顯用戶選擇的 php 選項。有沒有辦法縮短代碼?
uj5u.com熱心網友回復:
我放置
do_something函式的 case 陳述句部分看起來很亂,所有函式所做的就是用顏色回顯用戶選擇的 php 選項。有沒有辦法縮短代碼?
看來您正在適應用戶通過鍵入其編號或鍵入專案文本來選擇選項的雙重可能性。一種簡化是要求用戶僅按專案編號進行選擇,在這種情況下,您只需確認$php_opt未將其設定為 NULL。case根本不需要該宣告。
如果你想保留當前腳本的完整輸入功能,那么你仍然可以比當前代碼做得更好。而不是一個case涵蓋所有選項的長陳述句,檢查是否$php_opt為NULL,如果是,檢查是否$REPLY等于其中一個選項。有多種方法可以實作,但我喜歡這個:
validate_option() {
local choice=$1
while [[ $# -gt 1 ]]; do
shift
[[ "$choice" = "$1" ]] && return 0
done
return 1
}
# ...
select php_opt in "${options[@]}"; do
if [[ -n "$php_opt" ]] || validate_option "$REPLY" "${options[@]}"; then
do_something
fi
done
我覺得這樣清楚多了。還要注意該validate_option函式是可重用的,并且這種方法完全由選項串列驅動,因此如果選項串列發生變化,您無需修改??此代碼。
附錄
您還提出了一個問題,do_something即當用戶輸入選項值而不是其編號時,您的給定函式不會列印所選選項。這也將是您原始代碼的行為。它源于這樣一個事實,即如果用戶輸入不是選單項編號之一的非空回應,則該select命令將指定的變數(php_opt在您的情況下)設定為 NULL。
如果您想避免這種情況,并且可能還希望將選項字串形式的選定值用于其他后續處理,那么您可能希望在select陳述句正文中解決該問題。像這種變化可能會做,例如:
select php_opt in "${options[@]}"; do
if [[ -n "$php_opt" ]] ||
{ php_opt=$REPLY; validate_option "$php_opt" "${options[@]}"; }; then
do_something
fi
done
$php_opt如果用戶輸入了選項編號以外的內容,則將用戶輸入的文本復制到其中。請注意,行為更改也可能在腳本的后面產生其他影響。
uj5u.com熱心網友回復:
您要檢查的是 $php_opt 或 $REPLY 是否在 $options 陣列中:
array_contains() {
local -n ary=$1
local elem=$2
local IFS=$'\034'
[[ "${IFS}${ary[*]}$IFS" == *"${IFS}${elem}$IFS"* ]]
}
#...
select php_opt in "${options[@]}"; do
if array_contains options "$php_opt" || array_contains options "$REPLY"; then
do_something
break
fi
done
local -n 需要 bash v4.3
八進制 034 是 ASCII“FS”字符,它不太可能出現在您的資料中
uj5u.com熱心網友回復:
select僅當做出有效選擇時,才將給定的變數名稱設定為選定的字串。如果進行了無效選擇(即不是可用數字之一),則為$php_opt空。即使在之前的迭代中做出了有效的選擇,它也會被重置為空。
因此,您只需要測驗是否$php_opt為空:
select php_opt in "${options[@]}"; do
# check for literal reply
reply=${REPLY,,}
for i in "${options[@]}"; do
if [[ "$i" == "$reply" ]]; then
php_opt=$reply
break
fi
done
if [[ "$php_opt" ]]; then
do_something
break
else
echo "$REPLY: invalid selection"
fi
done
或與case:
select php_opt in "${options[@]}"; do
# check for literal reply
reply=${REPLY,,}
for i in "${options[@]}"; do
if [[ "$i" == "$reply" ]]; then
php_opt=$reply
break
fi
done
case $php_opt in
'') echo "$REPLY: invalid selection";;
*) do_something; break
esac
done
來自help select:
如果該行包含與顯示的單詞之一對應的數字,則將 NAME 設定為該單詞。如果該行為空,則重新顯示 WORDS 和提示。如果讀取 EOF,則命令完成。讀取的任何其他值都會導致 NAME 設定為 null。讀取的行保存在變數 REPLY 中。
另請注意,您$的 if 陳述句中缺少您。
編輯:根據評論,我添加了對文字名稱和數字的檢查。它不區分大小寫,PHP7.0是有效輸入。與 case 陳述句中的第二個模式串列相比,使用原始陣列更容易維護。
為了使事情更整潔,您也可以放在do_something 后面 select(因此您只需要break)。也許也有類似的東西[[ "$reply" == [Qq] ]] && exit。同樣,在您的第一個 case 陳述句中,exit如果回答是否定的,則執行。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/351964.html
下一篇:包含在資料摘要中的函式錯誤
