grep 查找 ipv4 作为单词而不是行

grep 查找 ipv4 作为单词而不是行

我必须在文件中找到 ipv4。问题是如果 IP 同一行上有其他单词,脚本将无法打印它。这是我的脚本:

#!/bin/bash


if [ -e ip.txt ]
then
    grep -E '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' ip.txt
else
    echo "file not found"
fi

现在,如果我有类似的内容,脚本将不会打印 IP:

198.54.34.6 text

答案1

从命令中删除^and并使用grep 命令的标志,即:$-o

grep -Eo '(^| )(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($|[[:space:]])'

例子:

echo 'some text 198.54.34.6 and test' | grep -Eo '(^| )(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($|[[:space:]])'

输出是:

 198.54.34.6

它会给出空格,也尝试使用 删除它们tr,例如command1 | tr -d " "

答案2

^$分别在行首和行尾匹配,因此只有当 IP 地址同时位于行首和行尾时,具有这些 IP 地址的行才会匹配,即如果 IP 地址整条线。

现在,如果您想匹配包含整个 IP 地址的行单词, 在哪里是空白分隔的,你可以使用:

d='[01234567890]'
n="($d|[123456789]$d|1$d$d|2[01234]$d|25[012345])"
grep -E "(^|[[:blank:]])$n\.$n\.$n\.$n([[:blank:]]|\$)" ip.txt

(这里也将那些替换[0-9][0123456789]经常[0-9]匹配的内容,而不仅仅是 0123456789)。

请注意,grep输出线那场比赛。如果您只想输出部分行,则需要使用类似sedor的东西perl(流编辑器),或者使用某些实现的一些非标准扩展,grep例如-oGNU 的grep

这里使用负环视运算符((?<!\H)意​​思是“前提是它前面没有非空白”(?!\H)相同,但向前看而不是向后看,(?1)回想起第一组中的 RE (...),所有类似 perl 的运算符都启用-P

grep -Po '(?<!\H)(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.(?1)\.(?1)\.(?1)(?!\H)' ip.txt

这相当于:

perl -lne 'print for
  /(?<!\H)(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.(?1)\.(?1)\.(?1)(?!\H)/g'

答案3

要仅打印 IPv4,您可以提取与-ogrep 选项匹配的内容。

作为一个更简单的例子,你可以这样做:

$ echo "this is a simple test to extract 123.234.34.5 as an IP" | 
       grep -o '[0-9.]*'

123.234.34.5

但这将失败恰恰匹配一个 IPv4。

使用正则表达式匹配 IP 有点复杂。正则表达式不理解数字范围,只理解文本。我们可以将一个 0-255 的数字值与(忽略空格和注释的正则表达式)匹配:

25[012345]                       | # the numers 250 - 255 or
2[01234](?P<digit>[0123456789])  | # 200 - 249 or
1(?&digit){2}                    | # 100 - 199 or
#0?                                 # Allow leading zero
[1-9](?&digit)                   | #  10 -  99 or
#0{0,2}                             # Allow leading zeros
(?&digit)                          #   0 - 9

删除第一列注释以包含前导零。

为了避免重复[0-9],使用显式数字范围(避免匹配其他语言中的数字)并为每个匹配组命名,我们可以使用 PCRE 中的“命名捕获组”:

(?P<byte>                             # Define this as one full byte value.
25[012345]                          | # the numers 250 - 255 or
2[01234](?P<digit>[0123456789])     | # 200 - 249 or
1(?&digit){2}                       | # 100 - 199 or
#0?                                    # Allow leading zero
[1-9](?&digit)                      | #  10 -  99 or
#0{0,2}                               # Allow leading zeros
(?&digit)                             #   0 - 9
)                                     # close one full byte definition

然后我们只需要重复使用带有前导点的字节定义(\.(?&byte)){3}三次以及一些前导和尾随标记,如下所示此链接中显示

\b如果需要的话,前导和尾随标记可以是更简单的“单词边界”( )在这个其他链接中显示

在 shell 中,使用 grep PCRE 正则表达式,命令可以写为:

$ grep -oP '(?xm)(?<=^|[^01234567890.])(?P<byte>25[012345]|2[01234](?P<digit>[0123456789])|[01]?(?&digit){1,2})(\.(?&byte)){3}(?=[^01234567890.]|$)' <<<"$a"
1.2.3.4
11.22.33.44
123.234.34.5
1.1.192.168
123.234.34.123
123.234.34.123
1.2.3.255
255.255.255.255
1.1.168.192
1.14.2.90
1.2.3.4

鉴于测试字符串包含:

$ a='1.2.3.4
11.22.33.44
123.234.34.5
1.1.192.168
text 123.234.34.123 more text
text123.234.34.123more text
1.2.3.255
1.2.3.256
255.255.255.255
256.2.3.4
1123.234.34.123
123.234.34.1235
.123.234.34.123
123.234.34.123.
not 1.1.168.192 in 1.1.168.192.in-addr.arpa.
not 1.14.2.90 in xserver-common_1.14.2.901-2_all.deb
1.2.3.4'

答案4

此正则表达式将获取 IP 地址,并且是 IPv4 地址的相当准确的正则表达式,grep -P打开 PCRE 正则表达式引擎并-o仅返回匹配的文本:

grep -Po '\b((?:25[0-5]|[2][0-4][0-9]|[1][0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|[2][0-4][0-9]|[1][0-9]{2}|[1-9][0-9]|[0-9])\b' ip.txt

有关此正则表达式的解释请参阅:https://regexr.com/4kjg4

25[0-5]          | # 250 - 255 
[2][0-4][0-9]    | # 200 - 249 
[1][0-9]{2}      | # 100 - 199 
[1-9][0-9]       | #  10 - 99
[0-9]            | #   0 - 9

相关内容