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

时间:2017-12-13 03:17:43

标签: regex bash ubuntu ip ifconfig

我这里有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输出的相关行的一部分。

4 个答案:

答案 0 :(得分: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:上的匹配不会包含在"匹配的文字中#34;由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保留的专用网络块中提取地址,包括环回。

答案 1 :(得分:3)

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

但是,为了回答字面而不重写命令或强加个人偏好,只需指定界面即可实现排除环回地址所需的结果想要获取ifconfig的第一个参数。默认情况下(即没有args),ifconfig会显示所有当前活动界面的状态。

这样的事情应该足够了:

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

man ifconfig

  

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

答案 2 :(得分:1)

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

  1. 正则表达式也匹配环回,因为它也是带有init addr:前兆的IP。
  2. 由于我echo $ipa代替"echo "$ipa",我们添加了空格。
  3. 鉴于我也获得了环回,因为正则表达式也匹配它(我在开始时没有注意到它,因为它接近ifconfig输出的结尾,我做的是使用{{ 1}} grep参数。这个参数使-m1只带来第一个匹配(外部IP确实更早,先发现),所以结束命令是:

    grep

    然而,正如Triplee的评论一样,原则上假设第一场比赛是外部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的这个单一ifconfig解决方案,涉及否定断言

    grep

    或者Triplee的一个较短的替代方案,它通过执行ipa=$(ifconfig | grep -Po 'inet addr:\K(?!127\.)\d{1,3}.\d{1,3}\.\d{1,3}\.\d{1,3}') 在交互式shell中启用历史扩展防护

    set +H

    注意:如果出现错误,则需要执行ipa=$(ifconfig | grep -Po 'inet addr:\K(?!127\.)[.\d]+') 。尽管可以使用set +H撤销此状态,但保持此状态没有问题。

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

    grep

答案 3 :(得分:0)

排除以127.开头的地址:

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

排除lo适配器:

ifconfig | perl -nle'BEGIN { $/="" } next if /^lo\b/; print for /\binet addr:(\S+)/g'

只是一个特定的适配器:

ifconfig eth1 | grep -Po '\binet addr:\K\S+'

以太网适配器的第一个地址,只有一个:

ifconfig | perl -nle'BEGIN { $/="" } if (/^eth.*?\binet addr:(\S+)/s) { print $1; exit; }'