2

我想创建一个脚本,将新域添加到我们的 DNS 服务器。我发现完全限定域名验证REGEX。但是,当我将它与 sed 一起使用时,它并没有像我预期的那样工作:

echo test | sed  '/(?=^.{5,254}$)(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(:[a-zA-Z]{2,})$)/p'  
--------
Output is: 
test
echo test.com | sed  '/(?=^.{5,254}$)(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(:[a-zA-Z]{2,})$)/p'  
--------
Output is: 
test.com

我希望第一个命令的输出应该是一个空行。我做错了什么?

4

6 回答 6

12

我发现这是一个更全面的正则表达式:

(?=^.{4,253}$)(^(?:[a-zA-Z0-9](?:(?:[a-zA-Z0-9\-]){0,61}[a-zA-Z0-9])?\.)+([a-zA-Z]{2,}|xn--[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])$)

  • RFC 1034§3:允许长度为 4-25 3,我所知道的最短操作域“t.co”仍然匹配其他答案不匹配的地方。255 字节是最大长度,减去每个标签(TLD 和“主”子域)的长度字节为 253:(?=^.{4,253}$)
    • RFC 3696§2:单字母 TLD技术上是允许的,这意味着最小长度为 3,但由于目前没有单字母 TLD,最小长度为 4 是可行的。
  • RFC 1034§3:允许子域中的数字,而 Conor Clafferty 显然不允许(通过不区分其他子域与“主要”子域 - 即您注册的域 - DNS 规范没有)
  • RFC 1034§3:将单个标签限制为 63 个字符,允许在中间使用连字符,同时将开头和结尾限制为字母数字(?:[a-zA-Z0-9](?:(?:[a-zA-Z0-9\-]){,61}[a-zA-Z0-9])?\.)
  • 需要两个字母或更大的 TLD,但可能是punycoded ([a-zA-Z]{2,}|xn--[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])
    • RFC 3696§2:DNS 规范在技术上允许 TLD 中的数字以及单字母 TLD;但是,目前没有单字母 TLD 或带数字的 TLD,并且不允许使用全数字 TLD,因此这部分正则表达式已简化为[a-zA-Z]{2,}.

      - 或者 -

    • RFC 3490§5:国际化域名 ccTLD (IDN c​​cTLD) 可能是 punycoded,如“xn--”前缀所示,其后可能包含字母、数字或连字符。这近似于xn--[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]

      请注意,此模式不会验证punycode TLD!将容忍无效的 punycode,例如“xn--qqqq”,因为尝试根据适当的编码机制验证 punycode 超出了正则表达式的范围。虽然 punycode 本身在技术上允许以连字符结尾的编码字符串,但RFC 3492§5遵守并尊重标签不能以连字符结尾的 IDNA 限制。

编辑 02/2021:向user2241415 致敬,指出 IDN c​​cTLD 与先前指定的正则表达式不匹配。

于 2014-11-10T18:02:57.180 回答
3

You are missing a question mark in your regex :

(?=^.{5,254}$)(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})$)

You can test your regex here

You can do what you want with grep :

$ echo test.com | grep -P '(?=^.{5,254}$)(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})$)'
test.com
$ echo test | grep -P '(?=^.{5,254}$)(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})$)'
$
于 2013-03-07T13:20:46.780 回答
1

sed我知道没有实现支持您在该正则表达式中使用的各种 Perl 扩展。尝试使用 Perl 或grep -Por pcregrep,或将正则表达式简化为sed可以处理的东西。这是一个快速而肮脏的改编,它将正则表达式拆分为三个不同正则表达式的脚本,并在某些内容无法匹配(或匹配,在最中间的情况下)时拒绝。

echo 'test' | sed -r '/^.{5,254}$/!d
    /^([^.]*\.)*[0-9]+\./d   # Seems incorrect; 112.com is valid
    /^([a-zA-Z0-9_\-]{1,63}\.?)+([a-zA-Z]{2,})$/!d'  # should disallow underscore
    # also, what's with the question mark after the literal dot?

这也完全无法接受 IDNA 域(其中可以包含 TLD 中的破折号和数字等)所以我绝对不推荐这个,但希望它向您展示如何适应这样的东西,sed如果您愿意的话。

于 2015-02-17T12:50:48.103 回答
0

Pierre-Louis 的回答对我不太适用。例如,“小猫”被视为域名。我添加了一个细微的调整,以确保域中至少有一个点。

(?=^.{5,254}$)(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+\.(?:[a-z]{2,})$)

\.在它读取域的最后一部分之前有一个额外的。

于 2013-08-07T13:21:29.720 回答
0

grep -P用来做这个。

echo test | grep -P "^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$" 
--------
Output is: 

echo www.test.com | grep -P "^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$"
--------
Output is: www.test.com
于 2016-10-06T17:17:05.847 回答
-2

如果域必须存在,您可以尝试:

$ cat test.sh
#!/bin/bash

for h in "bert" "ernie" "www.google.com"
do
    host $h 2>&1 > /dev/null
    if [ $? -eq 0 ]
    then
        echo "$h is a FQDN"
    else
        echo "$h is not a FQDN"
    fi
done

jalderman@mba:/tmp$ ./test.sh 
bert is not a FQDN
ernie is not a FQDN
www.google.com is a FQDN
于 2020-02-05T22:19:51.077 回答