我正在编写一些 shell 脚本,要求用户提供域名。我想提示用户循环输入,如果输入不是有效的域名,则写入错误消息。
基本上,代码应如下所示:
#!/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
的 in 条件部分,因此每次在正则表达式测试之前都会运行它,但我们不检查其退出状态。它是条件部分(此处或)中运行的最后一个命令,决定循环的分支。while
until
[[ ... ]]
! [[ ... ]]
另请记住,您不能使用字符范围进行输入验证,除非您将语言环境修复为 C 或切换到 zsh 等 shell,其中范围基于代码点。
#! /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
)。
如果使用=~
in 进行正则表达式匹配zsh
(而不是与 进行全局模式匹配=
),您需要确保通过使用该rematchpcre
选项来使用 PCRE。默认情况下,您会像 bash 一样获得 ERE,但有其所有限制。但请记住,PCRE 与 ERE 的等价物$
是\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
without-r
和 withoutIFS=
几乎没有任何意义。 echo
不应该用于输出任意数据。- 错误应该发送到 stderr