我必须在文件中找到 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
输出线那场比赛。如果您只想输出部分行,则需要使用类似sed
or的东西perl
(流编辑器),或者使用某些实现的一些非标准扩展,grep
例如-o
GNU 的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,您可以提取与-o
grep 选项匹配的内容。
作为一个更简单的例子,你可以这样做:
$ 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