Regex grep外部IP还带回了内部IP - 为什么?

问题描述 投票:2回答:4

我在这里有grep操作,它从ifconfig的输出中提供外部IP:

ipa=$(ifconfig | grep -Po "inet addr:\K[^\s]+" | grep -v "^127")

我只想使用一个grep,所以我尝试了以下,部分成功:

ipa=$(ifconfig | grep -Po "inet addr:\K[0-9]{1,3}?\.[0-9]{1,3}?\.[0-9]{1,3}?\.[0-9]{1,3}?")

它部分成功,因为它还带来了空间加上内部IP,原因如下:

MY_IP_ADDRESS 127.0.0.1

为什么会这样?我的意思是,为什么还添加了空间+环回,以及如何在仍然使用单个grep时可以采取哪些措施来防止这种情况?环回甚至不是ifconfig输出的相关行的一部分。

regex bash ubuntu ip ifconfig
4个回答
4
投票

鉴于您已经在使用grep -P,您可以简单地添加一个否定断言:

ipa=$(ifconfig | grep -Po 'inet addr:\K(?!127\.)\d{1,3}.\d{1,3}\.\d{1,3}\.\d{1,3}')

原始问题的正则表达式(因此编辑)也会在点之间接受零数字;我也修复了这个问题,并简化了结果,希望略微提高易读性。

\K是一个Perl创新,它说“如果你匹配到这里,忘记达到这一点的文本”,这意味着inet addr:上的匹配将不会包含在由grep -o打印的“匹配文本”中。

表达式(?!127\.)是一个负面的先行断言。简而言之,它说“如果这个正则表达式现在匹配,这不是匹配”。换句话说,正则表达式引擎会暂停一下,记下它在文本中的位置,然后“向前偷看”并尝试匹配127\.。如果成功,它会在此时放弃尝试匹配,并继续尝试在字符串中的稍后点匹配整个表达式(因此如果要在同一行中找到第二次出现的inet addr:,你仍然可以从那里得到一个匹配)。

最后,我将引号改为单引号。它在这里并不重要,但我推荐所有正则表达式unless you specifically require the shell to perform variable replacements in the regex或类似的单引号。

至于解释你所看到的内容,输出中确实没有空间。 grep输出两行,因为它找到两个匹配(当然我们现在使用负前瞻来防止;但如果你配置了多个接口,你仍然可以获得多个结果)。如果你看到一个空格,那是因为你在回声时没有使用双引号,就像在echo "$ipa"中一样。

如评论中所述,如果你得到bash: !127: event not found,你需要set +H或将命令放在脚本中;或者,使用我在上一段中推荐的单引号。除非你沉迷于传统的Csh-style history management features in Bash(严肃地说,现在是谁?),我建议你通过在set +H或类似的命令中使用命令.bash_profile来使这个变化永久化。

可选:重构正则表达式

你可以重构你的正则表达式,使其更紧凑,但可能稍微不易清晰:

ipa=$(ifconfig | grep -Po 'inet addr:\K(?!127\.)\d{1,3}(?:.\d{1,3}){3}')

更短的方式是:

ipa=$(ifconfig | grep -Po 'inet addr:\K(?!127\.)[.\d]+')

请注意相同的\K(?!127\.)模式,以及替换[.\d]+模式的新\d{1,3}.\d{1,3}\.\d{1,3}\.\d{1,3}')。这稍微不那么精确,但对于这种情况可能已经足够好了。如果您的输入来自ifconfig并且您已经看过inet addr:路标,那么匹配尽可能多的数字和点应始终为您提供所需的IP地址。

根据您的需要,您仍然可以在前瞻中添加更多要阻止的内容。为了防止它也匹配内部网络,像

(?!127\.|10\.|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168\.)

将阻止在所有IANA保留的专用网络块中提取地址,包括环回。


3
投票

有几种方法可以实现这一点,使用ifconfigipdig或我个人最喜欢的myip。此外,还有更多方法可以优化你的正则表达式,其中许多你可能已经在你的previous question的评论中看到过。

但是,要从字面上回答你,不重写你的命令或强加个人偏好,你可以通过简单地指定你想要获得的接口作为ifconfig的第一个参数来实现排除环回地址的预期结果。默认情况下(即没有args),ifconfig显示所有当前活动接口的状态。

这样的事情应该足够了:

# Replace "eth0" with the appropriately configured static inet address' interface
# ... is your `grep` pipe
ifconfig "eth0" ...

男人ifconfig

如果没有给出参数,ifconfig将显示当前活动接口的状态。


1
投票

正如Triplee在评论中指出的那样(Triplee的回答应该被推翻):

  1. 正则表达式也匹配环回,因为它也是带有init addr:前体的IP。
  2. 由于我做echo $ipa而不是"echo "$ipa",这个空间被添加了。

鉴于我也得到了环回,因为正则表达式也匹配它(我在开始时没有注意到它,因为它接近ifconfig输出的结尾,我做的是使用grep -m1参数。这个论点使grep到只带来第一个匹配(并且外部IP确实更早,并且首先找到),因此结束命令是:

ipa=$(ifconfig | grep -Po -m1 "inet addr:\K[0-9]{1,3}?\.[0-9]{1,3}?\.[0-9]{1,3}?\.[0-9]{1,3}?")

然而,正如Triplee的评论一样,原则上假设第一场比赛是外部IP并且不是环回--- ifconfig明天可能会改变,将环回作为第一场,这是一个问题,所以应该使用这个Triplee的单一grep解决方案涉及否定断言:

ipa=$(ifconfig | grep -Po 'inet addr:\K(?!127\.)\d{1,3}.\d{1,3}\.\d{1,3}\.\d{1,3}')

或者是Triplee的一个较短的替代方案,它还涉及通过执行qazxsw poi在交互式shell中防止历史扩展:

set +H

注意:出现错误时需要执行ipa=$(ifconfig | grep -Po 'inet addr:\K(?!127\.)[.\d]+') 。保持这种状态没有问题虽然可以用set +H撤销。

无论哪种方式,另一种最小的方法是我在问题中发表的原始2 set -H方法:

grep

0
投票

排除以qazxsw poi开头的地址:

ipa=$(ifconfig | grep -Po "inet addr:\K[^\s]+" | grep -v "^127")

不包括127.适配器:

ifconfig | grep -Po '\binet addr:\K(?!127\.)\S+'

只是一个特定的适配器

lo

只是以太网适配器的第一个地址,其中一个:

ifconfig | perl -nle'BEGIN { $/="" } next if /^lo\b/; print for /\binet addr:(\S+)/g'
© www.soinside.com 2019 - 2024. All rights reserved.