Извлечь строку из множества скобок - PullRequest
1 голос
/ 07 марта 2019

У меня есть файл с таким содержанием:

    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", 
    ]
}

Мне нужно извлечь IP между [], если в stout_line содержится kernel*.

Я хочу «эмулировать» подстроку, чтобы сохранить «блок» содержимого в переменную и просмотреть весь файл.
Как бы я использовал sed или другое, чтобы сделать это, если у меня много разделителей?

Ответы [ 7 ]

3 голосов
/ 07 марта 2019

A 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

Тот же вывод.tolower s для сопоставления без учета регистра. Если вы хотите точное совпадение, вы можете удалить их или просто использовать решения из 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, если вам не нужно регистронезависимое совпадение.

2 голосов
/ 07 марта 2019
$ 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
1 голос
/ 08 марта 2019

Это может работать для вас (GNU sed):

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

Установить -n для подавления неявной печати

Если строка содержит строку ok:, этоIP-адрес, лишить линии всего, кроме целых чисел и точек.

Добавляйте дополнительные строки до тех пор, пока не встретится строка, содержащая ], и если пространство шаблона содержит и stdout_line, и kernel, выведите первую строку.

1 голос
/ 07 марта 2019

, поскольку ваши данные в значительной степени хорошо отформатированы, вы можете использовать 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

Примечание :

  • Я настроилрегулярные выражения для отражения ваших обновленных данных.
  • вы можете получить более одного файла ядра для одного и того же IP-адреса в блоке out.stdout_lines, что даст один и тот же IP-адрес несколько раз.Если это произойдет, просто передайте результат в | uniq
0 голосов
/ 08 марта 2019

Использование 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

$
0 голосов
/ 07 марта 2019

Не могли бы вы попробовать следующее, это должно работать для большинства из awk s, я считаю. (Я добавил [kK] в условии соответствия, поэтому он должен искать kernal ИЛИ Kernal обе строки (так как OP предыдущий образец имел капитал K, а теперь он имеет k маленький, так что мы решили охватить оба здесь).

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
0 голосов
/ 07 марта 2019

Быстрое решение: #! / Bin / Баш

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