Bash

用於使用者輸入的 Bash While 循環和帶有最大嘗試次數計數器的錯誤提示

  • October 5, 2021

我創建了一個 while 循環來獲取使用者輸入並在出現錯誤時重複提示。

while true; do
       read -p "Enter hostname : " fqdn
       pattern="(^[^\.]*\.[^\.]*\.[^\.]*$)"
       
       if [[ -z "$fqdn" ]]; then   #if fqdn input is empty
               echo "Error! Hostname cannot be empty"
               continue
       elif [[ ! "${fqdn}" =~ ${pattern} ]]; then
               echo "Error! Format incorrect"
               continue
       else
               echo "hostname is $fqdn"
               break
       fi
done

我的目標:

  1. if/elif語句的情況下,如何只顯示兩次提示然後退出。
  2. 有沒有辦法可以改進上述 while 循環,例如使用 case switch。我覺得 case switch 很難理解?

作業系統:Ubuntu 20.04(無頭)

這是我心中的一個替代方案,我相信它可以改進:

# declare the pattern outside the loop
pattern="(^[^.]*\.[^.]*\.[^.]*$)"
# declare a counter for failed attempts
c=0

while true; do
 # if counter is equal to 2 exit
 [[ $c -eq 2 ]] && echo "Two failed attempts. Exiting" && exit

 read -p "Enter hostname : " fqdn

 if [[ -z "$fqdn" ]]; then
   echo "Error! Hostname cannot be empty"
   ((c++)) # increment the counter
   continue
 elif [[ ! "${fqdn}" =~ ${pattern} ]]; then
   echo "Error! Format incorrect"
   ((c++)) # increment the counter
   continue
 fi
 
 # this lines will be executed only if the conditions passed
 echo "hostname is $fqdn"
 break
done

這些case構造不使用正則表達式,因此對於復雜的匹配,最好使用if elif..語句。

以下bash腳本從使用者讀取字元串並測試該字元串是否滿足您似乎想要強制執行的主機名條件。

語句中使用的兩個模式中的第一個case測試兩個點之間沒有字元的病態情況(這是我們不採取行動的模式)。我們使用第二個模式測試包含至少兩個點且兩端沒有點的字元串。僅當第二個模式與字元串匹配時,主機名變數fdqn才設置為字元串。請注意,字元串foo..bar匹配第二個模式,這就是我們搶先將雙點子字元串與第一個模式匹配的原因。

#!/bin/bash

unset -v count fdqn

while true; do
       read -p 'Enter hostname: ' -r

       case $REPLY in (*..*) ;; ([!.]*.*.*[!.]) fdqn=$REPLY; break; esac

       echo 'Invalid format' >&2

       count=$(( count + 1 ))
       [ "$count" -eq 2 ] && break
done

if [ -z "$fdqn" ]; then
       echo 'No valid hostname entered' >&2
       exit 1
fi

printf 'The hostname is "%s"\n' "$fdqn"

count變數跟踪使用者嘗試輸入字元串的次數。如果這個變數的值達到 2,我們就跳出循環。

case除非您想讓它成為可移植sh腳本(在這種情況下,您必須以不同的方式執行該語句),否則這裡沒有真正需要使用語句read。使用 中的萬用字元==,語句將如下所示。bash``case

if [[ $REPLY == *..* ]]; then
       :
elif [[ $REPLY == [!.]*.*.*[!.] ]]; then
       fdqn=$REPLY
       break
fi

&&如果第一個被否定,這兩個測試也可以使用。

if [[ $REPLY != *..* ]] && [[ $REPLY == [!.]*.*.*[!.] ]]; then
       fdqn=$REPLY
       break
fi

如果您想避免獲得包含三個點的主機名,請確保$REPLY不匹配*.*.*.*,就像它不應該匹配一樣*..*

引用自:https://unix.stackexchange.com/questions/670755