사용자 입력을 위한 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. 의 경우만약/엘리프프롬프트를 두 번만 표시한 다음 종료하는 방법을 보여줍니다.
  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해야 함 ) 여기서 문을 실제로 사용할 필요는 없습니다 . readglobbing 연산자를 사용할 ==때 명령문 bashcase다음과 같습니다.

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

&&이 두 테스트는 첫 번째 테스트가 음성인 경우 연결하는 데에도 사용할 수 있습니다.

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

세 개의 점이 포함된 호스트 이름을 얻지 않으려면 일치 하지 않아야 하는 것처럼 $REPLY일치하지 않는지 확인하십시오 .*.*.*.**..*

답변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...

관련 정보