【问题标题】:Extract string from many brackets从多个括号中提取字符串
【发布时间】:2019-07-29 16:50:30
【问题描述】:

我有一个包含以下内容的文件:

    ok: [10.9.22.122] => {
        "out.stdout_lines": [
            "cgit-1.1-11.el7.x86_64",
            "python-paramiko-2.1.1-0.9.el7.noarch",
            "varnish-libs-4.0.5-1.el7.x86_64",
            "kernel-3.10.0-862.el7.x86_64"
        ]
    }
    ok: [10.9.33.123] => {
        "out.stdout_lines": [
            "python-paramiko-2.1.1-0.9.el7.noarch"
        ]
    }

    ok: [10.9.44.124] => {
        "out.stdout_lines": [
            "python-paramiko-2.1.1-0.9.el7.noarch",
            "kernel-3.10.0-862.el7.x86_64"
        ]
    }

   ok: [10.9.33.29] => {
       "out.stdout_lines": []
   }
   ok: [10.9.22.28] => {
       "out.stdout_lines": [
        "NetworkManager-tui-1:1.12.0-8.el7_6.x86_64", 
        "java-1.8.0-openjdk-javadoc-zip-debug-1:1.8.0.171-8.b10.el7_5.noarch", 
        "java-1.8.0-openjdk-src-1:1.8.0.171-8.b10.el7_5.x86_64", 
        "kernel-3.10.0-862.el7.x86_64", 
        "kernel-tools-3.10.0-862.el7.x86_64", 
    ]
}

ok: [10.2.2.2] => {
    "out.stdout_lines": [
        "monitorix-3.10.1-1.el6.noarch", 
        "singularity-runtime-2.6.1-1.1.el6.x86_64"
    ]
}

ok: [10.9.22.33] => {
    "out.stdout_lines": [
        "NetworkManager-1:1.12.0-8.el7_6.x86_64",
        "gnupg2-2.0.22-5.el7_5.x86_64", 
        "kernel-3.10.0-862.el7.x86_64", 
    ]
}

如果stout_line包含kernel*,我需要提取[]之间的IP。

我想“模拟”子字符串,将内容的“块”保存到变量中并浏览所有文件。
如果我有很多分隔符,我将如何使用sed 或其他方法来执行此操作?

【问题讨论】:

  • 输出将是:“IP 10.9.44.124 包含内核”
  • 10.9.22.122 不应该打印?
  • 是的,对不起。我需要将所有 IP 保存到包含内核。

标签: bash awk sed scripting cut


【解决方案1】:

GNU awk 解决方案:

awk -F'\\]|\\[' 'tolower($3)~/"out.stdout_lines" *:/ && tolower($4)~/"kernel/{print "The IP " $2 " cointain Kernel"}' RS='}' file

输出:

The IP 10.9.22.122 cointain Kernel
The IP 10.9.44.124 cointain Kernel
The IP 10.9.22.28 cointain Kernel
The IP 10.9.22.33 cointain Kernel

我使用][ 作为FS 字段分隔符,并使用} 作为RS 记录分隔符。
因此 IP 将变为 $2
此解决方案取决于结构,这意味着 "out.stdout_lines" 需要在 [ip] 之后的字段中,就像您在示例中显示的那样。

另一种 GNU awk 方式,没有上述限制:

awk -F']' 'match(tolower($0),/"out\.stdout_lines": *\[([^\]]+)/,m){if(m[1]~/"kernel/)print "The IP " substr($1, index($1,"[")+1) " cointain Kernel"}' RS='}' file

相同的输出。 tolowers 用于不区分大小写的匹配,如果您想要完全匹配,可以删除它们或仅使用 Revision 6 的解决方案。

综合以上两种方式的优点,第三种方式

awk -F'\\]|\\[' 'match(tolower($0),/"out\.stdout_lines": *\[([^\]]+)/,m){if(m[1]~/"kernel/)print "The IP " $2 " cointain Kernel"}' RS='}' file

如果您不需要不区分大小写的匹配,请将 tolower($0) 更改为 $0

【讨论】:

  • 我尝试了新的解决方案,它有效,我尝试了修订版 6,我更喜欢它,因为它最快...¡¡谢谢!!
【解决方案2】:
$ gawk -v RS="ok: " -F " => " '$2 ~ /[Kk]ernel/ { printf "The IP %s contains Kernel\n", $1 }' file
The IP [10.9.22.122] contains Kernel
The IP [10.9.44.124] contains Kernel

【讨论】:

    【解决方案3】:

    由于您的数据格式非常正确,您可以使用 awk(gawk):

    awk '
        # get the ip address
        /ok:/ {ip = gensub(/[^0-9\.]/, "", "g", $2) }
    
        # check the stdout_lines block and print Kernal and ip saved from the above line
        /"out.stdout_lines":/,/\]/ { if (/\<[Kk]ernel\>/) print ip}
    ' file
    #10.9.22.122
    #10.9.44.124
    #10.9.22.28
    #10.9.22.28
    #10.9.22.33
    

    注意

    • 我调整了正则表达式以反映您更新的数据。
    • 您可能会在out.stdout_lines 块下为同一 IP 获得多个内核文件,这将多次产生相同的 IP。如果发生这种情况,只需将结果传送到| uniq

    【讨论】:

      【解决方案4】:

      这可能对你有用(GNU sed):

      sed -n '/ok:/{s/[^0-9.]//g;:a;N;/]/!ba;/stdout_line.*kernel/P}' file
      

      设置-n 禁止隐式打印

      如果一行包含字符串ok: 这是一个IP 地址,则去掉除整数和句点之外的所有内容。

      追加更多行直到遇到包含] 的行,如果模式空间同时包含stdout_linekernel,则打印第一行。

      【讨论】:

        【解决方案5】:

        快速解决方案: #!/bin/bash

        AWK='
            /^ok:/ { gsub(/^.*\[/,""); gsub(/].*$/,""); ip=$0 }
            /"Kernel-default/ { if (ip) print ip; ip="" }
        '
        awk "$AWK" INPUT
        

        【讨论】:

          【解决方案6】:

          您能否尝试以下操作,这应该适用于我相信的大多数awks。(我在条件匹配中添加了[kK],因此它应该查找kernalKernal 两个字符串(因为OP 的之前的样本有大写K,现在有ksmall 一个,所以想在这里涵盖两者。

          awk '
          /ok/{
             gsub(/.*\[|\].*/,"")
             ip=$0
          }
          /stdout_line/{
             found=1
             next
          }
          found && /[kK]ernel/{
             print ip
          }
          /}/{
             ip=found=""
          }
          '  Input_file
          

          说明:为上述代码添加说明。

          awk '                       ##Starting awk program here.
          /ok/{                       ##Checking condition if a line contains string ok in it then do following.
             gsub(/.*\[|\].*/,"")     ##Globally substituting everything till [ and everything till ] with NULL in current line.
             ip=$0                    ##Creating variable named ip whose values is current line value(edited one).
          }                           ##Closing BLOCK for ok string check condition.
          /stdout_line/{              ##Checking condition if a line contains stdout_line then do following.
             found=1                  ##Set value of variable named found to 1 here.
             next                     ##next will skip all further statements from here.
          }                           ##Closing BLOCK for stdout_line string check condition here.
          found && /[kK]ernel/{          ##Checking condition if variable found is NOT NULL and string Kernel found in current line then do following.
             print ip                 ##Printing value of variable ip here.
          }                           ##Closing BLOCK for above condition now.
          /}/{                        ##Checking condition if a line contains } then do following.
             ip=found=""              ##Nullify ip and found variable here.
          }                           ##Closing BLOCK for } checking condition.
          '   Input_file              ##Mentioning Input_file name here.
          

          输出如下。

          10.9.22.122
          10.9.44.124
          10.9.22.28
          10.9.22.28
          10.9.22.33
          

          【讨论】:

          • 此解决方案多次重复包含“内核”的 IP。示例:35 乘以 10.9.22.123
          • 对于您给定的示例,它有效。那么是不是你有多个相同的 ips 并且你想删除重复的?请确认一次?相信我,这应该是这里提供的最简单的解决方案之一,并且如果这里的要求很明确,我也看不到任何其他解决重复问题的答案,但如果你能确认我可以增强它。
          【解决方案7】:

          使用 Perl

          $ perl -0777 -ne 's!\[(\S+)\].+?\{(.+?)\}!$y=$1;$x=$2;$x=~/kernel/ ? print "$y\n":""!sge'  brenn.log
          10.9.22.122
          10.9.44.124
          10.9.22.28
          10.9.22.33
          
          $
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-11-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-01-26
            • 2021-11-20
            相关资源
            最近更新 更多