WHILE에서 UNTIL 루프 대신 Bash "=~" 연산자를 사용하세요.

WHILE에서 UNTIL 루프 대신 Bash "=~" 연산자를 사용하세요.

나는 사용자에게 도메인 이름을 묻는 쉘 스크립트를 작성 중입니다. 사용자에게 입력 내용을 반복하여 입력하고 유효한 도메인 이름이 아닌 경우 오류 메시지를 작성하라는 메시지를 표시하고 싶습니다.

기본적으로 코드는 다음과 같아야 합니다.

#!/bin/bash
 
read -p "Enter domain name: " DOMAIN_NAME

while [[ testing for valid domain name goes here ]]
do
  echo ''
  echo 'You entered an invalid domain name. Please re-enter.'
  echo '... more error message data ....'
  echo ''
  read -p "Enter domain name: " DOMAIN_NAME
done

echo "You entered domain name: $DOMAIN_NAME"

"=~" 연산자를 사용하여 정규식을 테스트하는 방법을 보여주는 몇 가지 예를 찾았습니다. 그러나 이러한 예는 모두 UNTIL루프를 보여줍니다. 질문에 대한 답변에 정규식을 사용하세요.Bash에서 정규식을 사용하여 유효한 (하위)도메인 확인, 예는 다음과 같습니다

# !/bin/bash

until [[ "$DOMAIN_NAME" =~ ^([a-zA-Z0-9](([a-zA-Z0-9-]){0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,5}$ ]]
do
  read -p "Enter domain name: " DOMAIN_NAME
done

echo "You entered domain name: $DOMAIN_NAME"

이 방법은 작동하지만 사용자가 잘못된 데이터를 입력한 경우 추가 오류 메시지를 작성하는 것은 간단하지 않습니다. 이러한 메시지는 루프 내부, 이전에 작성되어야 read하지만 첫 번째 반복에는 작성되지 않습니다.

이러한 이유로 나는 while위에 표시된 대로 루프를 작성하는 것이 좋습니다. until루프를 루프로 다시 작성할 while때 필요한 테스트 표현식을 부정하는 방법을 찾을 수 없습니다 .

답변1

until cmd동일합니다 while ! cmd.

여기서는 다음을 수행하세요.

until
  IFS= read -rep 'Enter domain name: ' domain
  [[ $domain =~ $regexp ]]
do
  printf>&2 'Invalid domain: "%s"\n' "$domain"
done

printf 'You entered: "%s"\n' "$domain"

그것은 다음과 같습니다:

while
  IFS= read -rep 'Enter domain name: ' domain
  ! [[ $domain =~ $regexp ]]
do
  printf>&2 'Invalid domain: "%s"\n' "$domain"
done

printf 'You entered: "%s"\n' "$domain"

또는:

while
  IFS= read -rep 'Enter domain name: ' domain
  [[ ! $domain =~ $regexp ]]
do
  printf>&2 'Invalid domain: "%s"\n' "$domain"
done

printf 'You entered: "%s"\n' "$domain"

루프의 조건부 부분에 /가 있으므로 read정규식 테스트 전에 매번 실행되지만 종료 상태를 확인하지는 않습니다. 루프의 분기를 결정하는 것은 조건부 섹션(여기 또는 )에서 실행되는 마지막 명령입니다.whileuntil[[ ... ]]! [[ ... ]]

또한 로케일을 C로 수정하거나 범위가 코드 포인트를 기반으로 하는 zsh와 같은 셸로 전환하지 않는 한 입력 유효성 검사에 문자 범위를 사용할 수 없다는 점을 명심하세요.

#! /bin/zsh -
set -o extendedglob
until
  domain=
  vared -p 'Enter domain name: ' domain
  [[ $domain = ([a-zA-Z0-9]([a-zA-Z0-9-](#c0,61)[a-zA-Z0-9]|).)##[a-zA-Z](#c2,5) ]]
do
  printf>&2 'Invalid domain: "%s"\n' "$domain"
done
printf 'You entered: "%s"\n' "$domain"

(여기서는 vared(var editor) 내장 기능을 사용하여 bash와 같은 zsh 라인 편집기를 사용합니다 read -e).

전역 패턴 일치를 위한 with 대신 =~정규식 일치를 위해 in을 사용하는 경우 이 옵션을 사용하여 PCRE를 사용하고 있는지 확인해야 합니다 . 기본적으로 bash와 같은 ERE를 얻을 수 있지만 모든 제한 사항이 있습니다. 하지만 PCRE는 ERE와 동일하다는 점을 기억 하세요 . 그래서:zsh=rematchpcre$\z

regexp='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,5}\z'

UTF-8 로케일에서 유효한 문자를 형성하지 않는 일련의 바이트는 PCRE 오류를 유발합니다. zsh glob 모드를 사용하면 이러한 문제를 보다 원활하게 처리할 수 있습니다.

Bash에서 C 로케일 외부에서 이 10개 문자만 일치시키려면(옵션 활성화 여부에 관계없이) [0123456789]대신 필요합니다. 또는와 같습니다. 적어도 bash에서는 변수에 NUL 바이트가 포함될 수 없으므로 해당 바이트와 일치하지 않는 정규 표현식에 대해 걱정할 필요가 없습니다.[0-9]globasciiranges[a-z][A-Z]

또한 기억하세요:

  • bash에서는 read없이 사용하거나 -r사용하지 않고 사용하는 것은 IFS=거의 의미가 없습니다 .
  • echo임의의 데이터를 출력하는 데 사용해서는 안됩니다.
  • 오류는 stderr로 전송되어야 합니다.

관련 정보