【问题标题】:Extract specific string between two strings and list the required content提取两个字符串之间的特定字符串并列出所需内容
【发布时间】:2017-10-04 06:53:38
【问题描述】:

如何找到可用字符串所在的块名?

server.conf 文件

server_pool odd {
    0:server1:yes:profile_server1:192.168.1.1,192.168.1.2;
    1:server3:yes:profile_server3:192.168.1.5,192.168.1.6;
}

server_pool even {
    0:server2:yes:profile_server2:192.168.1.3,192.168.1.4;
    1:server4:yes:profile_server4:192.168.1.7,192.168.1.8;
}

#server_pool even {
#    0:server1:yes:profile_server1:192.168.1.1,192.168.1.2;
#    1:server3:yes:profile_server3:192.168.1.5,192.168.1.6;
#}

注意事项:-

  1. “server_pool”是一个静态字符串
  2. “pool_name”可以是任何不带空格的字符串
  3. "如果一行有#,则忽略它

要求

  1. 需要通过提供的服务器主机名作为输入找到“pool_name”,即 server{1,2,3,} 并将其存储在变量中

例如

如果需要查找 server1 属于哪个块/节。在给定的用例中,它属于奇数,因此将变量存储为 POOLNAME=odd

【问题讨论】:

    标签: bash shell awk sed grep


    【解决方案1】:
    grep -oP '^server\s\K[^ ]+|^[^#]\s+\d+:\K[^:]+' inputfile
    pool0
    server1
    server2
    pool1
    server3
    server4
    

    【讨论】:

    • 如何在同一行的开头打印 pool0、pool1 以及静态字符串“server”
    • 请添加准确的样本输入以获得您想要的结果,因为此解决方案适用于最初提供的样本输入。
    • 我不知道可能是 RavinderSingh13 将其标记为重复问题,但我不认为这是重复问题。这是两个不同的要求
    • @asokan 这与接受答案有什么关系!! Ravindra 将始终公平行事,因为您澄清了您的问题没有被重复。请不要接受取悦任何人的答案,如果您认为它真的对您有帮助并且您将在您的程序中使用代码,那么请接受并投票。 .虽然这取决于你。它的好更好最好,不讨人喜欢。结束讨论,请勿回复。
    【解决方案2】:

    使用awk

    awk -F'[: ]+' '/}/{p=0}/^#|}/||!NF{next}/pool[0-9]+[ \t]+?{/{if(h)print "";p=1;print $2;next}p{print $3;h=1}' file
    

    更好的可读性:

    awk -F'[: ]+' '
                   # if line contains }, set variable p=0
    
                          /}/{ 
                                p=0;
                             }
    
                  # If line start with #, closing }, or empty line, skip
    
                /^#|}/ || !NF{ 
                                next 
                              }
    
                   # if line contains pool[0-9]+ can be space or tab and then {, 
                   # if variable h was set before
                   # print newline,
                   # set variable p =1, print 2nd field, go to next line
    
        /pool[0-9]+[ \t]+?{/{ 
                                if(h)print "";
                                p=1;
                                print $2;
                                next
                            }
    
                   # as long as p is set,
                   # print 3rd field from such record, 
                   # h =1, to have newline char when awk finds news pool
    
                           p{
                                print $3;
                                h=1
                            }
                  ' file
    

    这是测试结果:

    输入:

    $ cat file
    server pool0 {
            0:server1:yes:profile_server1:192.168.1.1,192.168.1.2;
            1:server2:yes:profile_server2:192.168.1.3,192.168.1.4;
    }
    
    server pool1 {
            0:server3:yes:profile_server3:192.168.1.5,192.168.1.6;
            1:server4:yes:profile_server4:192.168.1.7,192.168.1.8;
    }
    
    #server pool2 {
    #        0:server5:yes:profile_server5:192.168.1.9,192.168.1.10;
    #        1:server6:yes:profile_server6:192.168.1.11,192.168.1.12;
    #}
    

    输出:

    $ awk -F'[: ]+' '/\}/{p=0}/^#|\}/||!NF{next}/pool[0-9]+[ \t]+?\{/{if(h)print "";p=1;print $2;next}p{print $3;h=1}' file
    pool0
    server1
    server2
    
    pool1
    server3
    server4
    

    【讨论】:

    • 文件中还有其他块,例如client client_pool { 0:server3:yes:profile_server3:192.168.1.5,192.168.1.6; 1:server4:是:profile_server4:192.168.1.7,19​​2.168.1.8; } 它也选择了
    • @asokan,正如我已经要求的那样,请在您的帖子中使用代码标签向我们展示示例输入和预期输出。
    • @asokan:我看到它与您更新的新输入样本一起工作
    【解决方案3】:

    GRPNAME="服务器池0 {" GRPNAME=${GRPNAME%{*}; GRPNAME=${GRPNAME#*\ }

    where:
    ${GRPNAME%\{*} = delete everyting from end ("%") until 1st "{*"; the "\" is an escape character
    ${GRPNAME#*\ } = delete everything from beginning ("#")and stop after 1st space; ; the "\" is an escape character
    

    【讨论】:

      【解决方案4】:

      遵循 awk 可能会对您有所帮助。

      awk -F' +|:' '/^$/{flag="";next} /^server pool/{print $2;flag=1;next} flag && NF && !/}/{print $3}' Input_file
      

      编辑:如果您的池阻止了您可能有许多其他条目而不是服务器,那么我已经添加了一个额外的检查,请尝试并让我知道。

      awk -F' +|:' '/^$/{flag="";next} /^server pool/{print $2;flag=1;next} flag && NF && !/}/ && $3~/server/{print $3}'  Input_file
      

      EDIT2:向 OP 显示代码仅由 OP 提供预期的输出。

      awk -F' +|:' '/^$/{flag="";next} /^server pool/{print $2;flag=1;next} flag && NF && !/}/ && $3~/server/{print $3}' Input_file
      pool0
      server1
      server2
      pool1
      server3
      server4
      

      【讨论】:

      • 我忘了说文件中有不同的组名,比如“服务器”有“客户端”“磁盘”,我只需要“服务器”
      • @asokan,上面只会寻找服务器吗?您是说在块内您有客户端/磁盘等吗?您能否让我知道更多关于它在哪里不起作用的详细信息?
      • 文件中有不同的节,它还列出了那些客户端 cn01 cn02 main = = 并且在某些地方打印了“=”
      • @asokan,您能否检查我的编辑答案,我也不清楚,您能否在您的帖子中再次添加示例输入和预期输出(使用此新条件),并带有代码标签和那就告诉我们吧。
      • @asokan,我刚刚用你新编辑的数据检查了我的命令,它显示了你所期望的相同输出,现在看我的 EDIT2。
      【解决方案5】:
      egrep -o "^server pool[0-9]|^[^#][ ]+[0-9]:server[0-9]" file.txt | cut -d ':' -f2 | sed 's/\(server pool[1-9]\)/\n\1/g'
      

      输出

      server pool0
      server1
      server2
      
      server pool1
      server3
      server4
      

      注意

      我认为池总是从 0 开始,并且您不能拥有索引 > 9 的池。如果不是这种情况,您可以更改,例如 [0-9][0-9]{1,2} 以接受介于 -1 和100.

      【讨论】:

        【解决方案6】:

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

        sed -nr '/^(server \S+).*/{s//\1/p;:a;n;s/^(([^:]*):){2}.*/\2/p;ta}' file
        

        关注以server 开头的行并从这些行中提取前两个单词。从后续行中提取第二个字段(使用: 作为分隔符),直到发生匹配失败。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多