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に送信する必要があります。

関連情報