Extract specific string between two strings and li

2019-09-21 12:01发布

问题:

how to find the block name in which the string available ?

server.conf file

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;
#}

Notes:-

  1. "server_pool" is a static string
  2. "pool_name" can be any string without spaces
  3. "if a line has # in it ignore it

Requirement

  1. Need to find the "pool_name" by the provided server hostname as input i.e server{1,2,3,} and store it in a variable

for example

if need to find server1 belongs to which block/ stanza. in the given use case it belongs to odd, so store variable as POOLNAME=odd

回答1:

grep -oP '^server\s\K[^ ]+|^[^#]\s+\d+:\K[^:]+' inputfile
pool0
server1
server2
pool1
server3
server4


回答2:

Using 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

Better Readable:

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

Here is Test results:

Input:

$ 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;
#}

Output:

$ 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


回答3:

GRPNAME="server pool0 {" 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:

Following awk may help you in same.

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

EDIT: If your pool block you could have many other entries other than servers then I have added an additional check for it, try it and let me know then.

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

EDIT2: Showing OP that code is providing the expected output by OP only.

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


回答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'

Output

server pool0
server1
server2

server pool1
server3
server4

Note

I suppossed that pool are always starting by 0 and that you can not have pool with an index > 9. If that's not the case you can change, for example [0-9] to [0-9]{1,2} to accept number between -1 and 100.



回答6:

This might work for you (GNU sed):

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

Focus on lines that begin server and extract the first two words from such lines. From subsequent lines, extract the second field (using : as a separator) until a failure to match occurs.