Bash While 循环用于用户输入和错误提示,并带有最大尝试次数计数器

Bash While 循环用于用户输入和错误提示,并带有最大尝试次数计数器

我创建了一个 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. 的情况下如果/elif说明如何仅显示提示两次然后退出。
  2. 有没有办法可以改进上面的 while 循环,例如使用 案例开关。我觉得大小写切换很难理解?

操作系统:Ubuntu 20.04(无头)

答案1

以下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不同的方式执行该语句)。使用 globbing 运算==符时bashcase语句将如下所示。

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

&&如果第一个测试被否定,也可以使用这两个测试来连接。

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

如果您想避免获得包含三个点的主机名,请确保$REPLYdoes not match *.*.*.*,就像它不应该 match 一样*..*

答案2

我想到了一个替代方案,我相信它可以改进:

# 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..语句。

相关内容