phu*_*oft 0 shell-script regular-expression testing
我正在编写一些 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"
Run Code Online (Sandbox Code Playgroud)
我发现了一些示例,展示了如何使用“=~”运算符来测试正则表达式。然而,这些例子都显示了UNTIL循环。使用问题Check valid (sub)domain with regex in 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"
Run Code Online (Sandbox Code Playgroud)
虽然这可行,但在用户输入无效数据的情况下编写额外的错误消息并不简单。这样的消息必须写在循环内部,在 之前read,但不是在第一次迭代时。
出于这个原因,我宁愿将循环编写为while如上所示的循环。我无法找到如何否定测试表达式,这是将循环重写until为while循环时所需要的。
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"
Run Code Online (Sandbox Code Playgroud)
与...一样:
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"
Run Code Online (Sandbox Code Playgroud)
或者:
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"
Run Code Online (Sandbox Code Playgroud)
请注意,我们有/循环read的 in 条件部分,因此每次在正则表达式测试之前都会运行它,但我们不检查其退出状态。它是条件部分(此处或)中运行的最后一个命令,决定循环的分支。whileuntil[[ ... ]]! [[ ... ]]
另请记住,您不能使用字符范围进行输入验证,除非您将语言环境修复为 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"
Run Code Online (Sandbox Code Playgroud)
(这里使用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'
Run Code Online (Sandbox Code Playgroud)
请注意,在 UTF-8 语言环境中,未形成有效字符的字节序列将触发 PCRE 错误。使用 zsh glob 模式时可以更优雅地处理这些问题。
在 bash 中,在 C 语言环境之外,如果您只想匹配这 10 个字符(无论启用或不启用该选项),您需要[0123456789]而不是。与或相同。至少在 bash 中,变量不能包含 NUL 字节,因此您不必担心正则表达式无法匹配这些字节。[0-9]globasciiranges[a-z][A-Z]
还请记住:
readwithout-r和 withoutIFS=几乎没有任何意义。echo不应该用于输出任意数据。