Разбор стандартных блоков в массивы в bash или ruby - PullRequest
0 голосов
/ 27 марта 2020

Я пытаюсь найти наиболее эффективный способ преобразования записей журнала stdout из racadm (dell chassis / idra c) в отдельные массивы или json массивы, чтобы я мог оценивать каждую запись по одной за раз. Вывод всегда имеет одинаковые поля. Вывод ниже довольно типичен

$ racadm chassislog view -c Storage -b PDR
SeqNumber       = 11700
Message ID      = PDR17
Category        = Storage
AgentID         = CMC
Severity        = Information
Timestamp       = 2020-03-21 00:02:06
Message Arg   1 = Physical Disk 0:0:15
FQDD            = Disk.Bay.15:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1
Message         = Global hot spare assigned to Physical Disk 0:0:15.
--------------------------------------------------------------------------------
SeqNumber       = 11699
Message ID      = PDR26
Category        = Storage
AgentID         = CMC
Severity        = Information
Timestamp       = 2020-03-21 00:02:04
Message Arg   1 = Physical Disk 0:0:3
FQDD            = Disk.Bay.3:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1
Message         = Physical Disk 0:0:3 is online.
--------------------------------------------------------------------------------
SeqNumber       = 11696
Message ID      = PDR71
Category        = Storage
AgentID         = CMC
Severity        = Information
Timestamp       = 2020-03-21 00:02:01
Message Arg   1 = Physical Disk 0:0:15
Message Arg   2 = Physical Disk 0:0:3
FQDD            = Disk.Bay.15:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1
Message         = Copyback completed from Physical Disk 0:0:15 to Physical Disk 0:0:3.
--------------------------------------------------------------------------------
SeqNumber       = 11670
Message ID      = PDR70
Category        = Storage
AgentID         = CMC
Severity        = Information
Timestamp       = 2020-03-20 21:45:47
Message Arg   1 = Physical Disk 0:0:15
Message Arg   2 = Physical Disk 0:0:3
FQDD            = Disk.Bay.15:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1
Message         = Copyback started from Physical Disk 0:0:15 to Physical Disk 0:0:3.
--------------------------------------------------------------------------------
SeqNumber       = 11667
Message ID      = PDR8
Category        = Storage
AgentID         = CMC
Severity        = Information
Timestamp       = 2020-03-20 21:45:44
Message Arg   1 = Physical Disk 0:0:3
FQDD            = Disk.Bay.3:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1
Message         = Physical Disk 0:0:3 is inserted.
--------------------------------------------------------------------------------

Мне бы очень хотелось прочитать весь вывод в ассоциативный массив, чтобы я мог просмотреть каждую запись в для l oop для событий. Нужны указания в ruby (шеф-повар) или bash.

Ответы [ 3 ]

1 голос
/ 27 марта 2020

Этот perl однострочный конвертирует входные данные, как указано выше, в массив JSON объектов, которые затем можно обработать в любом JSON -осведомленном инструменте.

racadm chassislog view -c Storage -b PDR | \
perl -MJSON::PP -lne 'if (/([^=]*?)\s*=\s*(.*)/) { $obj{$1} = $2 }
                      elsif (/^-+$/) { push @records, { %obj }; undef %obj }
                      END { push @records, { %obj } if defined %obj;
                            print encode_json(\@records) }'

выходных данных (после довольно -печать):

[
  {
    "Timestamp": "2020-03-21 00:02:06",
    "Message ID": "PDR17",
    "Category": "Storage",
    "Message": "Global hot spare assigned to Physical Disk 0:0:15.",
    "AgentID": "CMC",
    "Severity": "Information",
    "SeqNumber": "11700",
    "FQDD": "Disk.Bay.15:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1",
    "Message Arg   1": "Physical Disk 0:0:15"
  },
  {
    "Category": "Storage",
    "Message ID": "PDR26",
    "Timestamp": "2020-03-21 00:02:04",
    "SeqNumber": "11699",
    "Message": "Physical Disk 0:0:3 is online.",
    "Severity": "Information",
    "AgentID": "CMC",
    "Message Arg   1": "Physical Disk 0:0:3",
    "FQDD": "Disk.Bay.3:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1"
  },
  {
    "FQDD": "Disk.Bay.15:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1",
    "Message Arg   2": "Physical Disk 0:0:3",
    "Message Arg   1": "Physical Disk 0:0:15",
    "Severity": "Information",
    "AgentID": "CMC",
    "Message": "Copyback completed from Physical Disk 0:0:15 to Physical Disk 0:0:3.",
    "SeqNumber": "11696",
    "Timestamp": "2020-03-21 00:02:01",
    "Category": "Storage",
    "Message ID": "PDR71"
  },
  {
    "Message Arg   1": "Physical Disk 0:0:15",
    "FQDD": "Disk.Bay.15:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1",
    "Message Arg   2": "Physical Disk 0:0:3",
    "SeqNumber": "11670",
    "Message": "Copyback started from Physical Disk 0:0:15 to Physical Disk 0:0:3.",
    "Severity": "Information",
    "AgentID": "CMC",
    "Category": "Storage",
    "Message ID": "PDR70",
    "Timestamp": "2020-03-20 21:45:47"
  },
  {
    "Timestamp": "2020-03-20 21:45:44",
    "Message ID": "PDR8",
    "Category": "Storage",
    "Message": "Physical Disk 0:0:3 is inserted.",
    "AgentID": "CMC",
    "Severity": "Information",
    "SeqNumber": "11667",
    "FQDD": "Disk.Bay.3:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1",
    "Message Arg   1": "Physical Disk 0:0:3"
  }
]
1 голос
/ 27 марта 2020

Не bash, поскольку оболочка предназначена для обработки файлов и запуска команд, но с использованием GNU awk, который часто ошибочно воспринимается как часть оболочки, это простой, но мощный язык программирования. пошаговое выполнение каждой записи в a для l oop для событий на самом деле не является обязательным требованием, поэтому приведу небольшой пример:

$ gawk -v item="Message Arg   2" '  # queried item as parameter 
BEGIN {
    RS="\n-+$\n"                    # record is separated by a bunch of -:s
    FS="\n"                         # a line is a field within a record
}
{
    for(nf=1;nf<=NF;nf++) {         # loop all lines in a record
        split($nf,t,/ *= */)        # split lines by = and surrounding space
        a[NR][t[1]]=t[2]            # hash to a 2 dimensional array indexed by
    }                               # record no. and the item, value as value
}
END {                               # after lines are hashed, make queries
    for(nr in a)                    # for each record in hash
        if(item in a[nr])           # if queried item is found in it
            printf "%d: %s = %s\n", nr,item,a[nr][item]  # output
}' file

Вывод для элемента запроса Message Arg 2:

3: Message Arg   2 = Physical Disk 0:0:3
4: Message Arg   2 = Physical Disk 0:0:3

Здесь альтернативное окончание для соответствует условию, которое я ищу в «сообщении». Я хотел бы сослаться на соответствующий FQDD :

$ gawk -v item=Message -v cond=started -v output=FQDD
BEGIN {
    RS="\n-+$\n"                    # record is separated by a bunch of -:s
    FS="\n"                         # a line is a field within a record
}
{
    for(nf=1;nf<=NF;nf++) {         # loop all lines in a record
        split($nf,t,/ *= */)        # split lines by = and surrounding space
        a[NR][t[1]]=t[2]            # hash to a 2 dimensional array indexed by
    }                               # record no. and the item, value as value
}
END {
    for(nr in a)
        if((item in a[nr]) && a[nr][item]~cond)
            printf "%d: %s = %s\n", nr,output,a[nr][output]
}

Вывести сейчас:

4: FQDD = Disk.Bay.15:Enclosure.Internal.0-0:RAID.ChassisIntegrated.1-1

ie. если переменная item найдена в a[nr][item] и значение этого элемента массива совпадает с cond, выведите значение a[nr]["FQDD"] в той же записи. В SQL это будет SELECT output FROMfileWHERE item LIKE '%cond%'

0 голосов
/ 27 марта 2020

Основываясь на шаблоне Shawns one liner, коллега в итоге нашел python 2.7 совместимый способ делать именно то, что нам нужно, код приведен ниже и предлагает именно ту функциональность, которая мне нужна.

import re
import json
from pprint import pprint

regex_string_1 = '([^=]*?)\s*=\s*(.*)'
regex_string_2 = '^-+$'
regex1 = re.compile(regex_string_1)
regex2 = re.compile(regex_string_2)
current_entry = {}
entries = []
lines = test.split('\n')
for line in lines:
    if regex1.match(line):
        key, value = [element.strip() for element in line.split('=')]
        current_entry[key] = value
    elif regex2.match(line):
        entries.append(current_entry)
        current_entry = {}
pprint(entries)
...