正则表达式 - >从复杂的字符串中提取固定位置的出现

时间:2017-06-12 16:32:19

标签: regex networking pattern-matching find-occurrences tinc

我有一个像下面这样的字符串(nvram extract),由tinc VPN用来定义网络主机:

1<host1<host1.network.org<<0<10.10.10.0/24<<Ed25519PublicKey = 8dtRRgAaTbUNtPxW9U3nGn6U7uvfIPwRo1wnx7xMIUH<Subnet = 10.10.3.0/24>1<host2<host2.network.org<<0<10.10.9.0/24<<Ed25519PublicKey = irn48tqF2Em4rIG0ggBmpEfaVKtkl6DmGdSzTHMmVEI<>0<host3<host3.network.org<<0<10.10.11.0/24<<Ed25519PublicKey = wQt1sFwOsd1hnBaNGHq4JDyib22fOg1YqzOp0p08ZTD<>

我试图从上面提取:

host1.network.org host2.network.org host3.network.org

组成主机名和键,但输入字符串的结构是准确的。顺便说一句,终端节点也可以被定义为IP地址,所以我试图提取第二次出现的&#34;&lt;&#34;之间的内容。并且第一次出现&#34;&lt;&lt;&#;;由于这是多重匹配,因此在行开头或&#34;&gt;&#34;之后计算事件。字符。所以上面的内容可以理解如下:

1<host1<host1.network.org<<0<10.10.10.0/24<<Ed25519PublicKey = 8dtRRgAaTbUNtPxW9U3nGn6U7uvfIPwRo1wnx7xMIUH<Subnet = 10.10.3.0/24>

1<host2<host2.network.org<<0<10.10.9.0/24<<Ed25519PublicKey = irn48tqF2Em4rIG0ggBmpEfaVKtkl6DmGdSzTHMmVEI<>

0<host3<host3.network.org<<0<10.10.11.0/24<<Ed25519PublicKey = wQt1sFwOsd1hnBaNGHq4JDyib22fOg1YqzOp0p08ZTD<>

由于我需要在shell脚本中使用此信息,我想我需要将每个主机/ IP存储为数组的元素。

我使用了regexp在线编辑器,并设法计算出这个字符串:

^[0|1]<.*?(\<(.*?)\<<)|>[0|1]<.*?(\<(.*?)\<)

但是我跑了

grep -Eo '^[0|1]<.*?(\<(.*?)\<<)|>[0|1]<.*?(\<(.*?)\<)'

反对最初的刺激我得到了完整的字符串作为回报所以我一定做错了: - /

P.S。在buysbox上运行: `BusyBox v1.25.1(2017-05-21 14:11:58 CEST)多调用二进制文件。

用法:grep [-HhnlLoqvsriwFE] [-m N] [-A / B / C N] PATTERN / -e PATTERN ... / - f FILE [FILE] ...

在文件(或标准输入)中搜索PATTERN

    -H      Add 'filename:' prefix
    -h      Do not add 'filename:' prefix
    -n      Add 'line_no:' prefix
    -l      Show only names of files that match
    -L      Show only names of files that don't match
    -c      Show only count of matching lines
    -o      Show only the matching part of line
    -q      Quiet. Return 0 if PATTERN is found, 1 otherwise
    -v      Select non-matching lines
    -s      Suppress open and read errors
    -r      Recurse
    -i      Ignore case
    -w      Match whole words only
    -x      Match whole lines only
    -F      PATTERN is a literal (not regexp)
    -E      PATTERN is an extended regexp
    -m N    Match up to N times per file
    -A N    Print N lines of trailing context
    -B N    Print N lines of leading context
    -C N    Same as '-A N -B N'
    -e PTRN Pattern to match
    -f FILE Read pattern from file`

谢谢!

2 个答案:

答案 0 :(得分:0)

您拥有的正则表达式基于捕获组,grep只能获得完整匹配。此外,你使用-E(POSIX ERE风味),而你的正则表达式实际上不兼容POSIX ERE,因为它包含这种风格不支持的惰性量词。

我认为您可以在<<之间提取所有非<<个字符,后跟一个数字,然后提取一个带有PCRE正则表达式的< -P }选项):

s='1<host1<host1.network.org<<0<10.10.10.0/24<<Ed25519PublicKey = 8dtRRgAaTbUNtPxW9U3nGn6U7uvfIPwRo1wnx7xMIUH<Subnet = 10.10.3.0/24>1<host2<host2.network.org<<0<10.10.9.0/24<<Ed25519PublicKey = irn48tqF2Em4rIG0ggBmpEfaVKtkl6DmGdSzTHMmVEI<>0<host3<host3.network.org<<0<10.10.11.0/24<<Ed25519PublicKey = wQt1sFwOsd1hnBaNGHq4JDyib22fOg1YqzOp0p08ZTD<>'
echo $s | grep -oP '(?<=<)[^<]+(?=<<[0-9]<)'

请参阅regex demogrep demo

输出:

host1.network.org
host2.network.org
host3.network.org

此处,(?<=<)是一个积极的外观,只检查当前位置左侧的<存在,但不会将<添加到匹配值{{1匹配除[^<]+<之外的1 +字符(正向前瞻)需要(?=<<[0-9]<),然后是数字,然后是<<,但同样不会添加这些字符到比赛。

如果<中没有PCRE选项,请尝试使用某些字符替换所有不需要的文本,然后使用awk拆分,或使用grep

grep

请参阅another online demo

答案 1 :(得分:0)

好的,我的评论没有回应,所以我会输入它作为答案。 <怎么样

grep -Eo '\w*[a-z]\w*(\.\w*[a-z]\w*)+'

它匹配至少完全限定名称的两部分,用点分隔。

{{1}}

产量

  

host1.network.org

     

host2.network.org

     

host3.network.org

(假设您的字符串是在stdin中输入的;)