Извлечь несколько строк, если они совпадают

Извлечь несколько строк, если они совпадают

У меня есть команда, которая выводит информацию обо всех слотах DIMM блоками, например следующими:

ID    SIZE TYPE
44    105  SMB_TYPE_MEMDEVICE (type 17) (memory device)

  Manufacturer: NO DIMM
  Serial Number: NO DIMM
  Asset Tag: NO DIMM
  Location Tag: P1-DIMMD1
  Part Number: NO DIMM

  Physical Memory Array: 43
  Memory Error Data: Not Supported
  Total Width: 0 bits
  Data Width: 0 bits
  Size: Not Populated
  Form Factor: 9 (DIMM)
  Set: None
  Rank: Unknown
  Memory Type: 2 (unknown)
  Flags: 0x4
        SMB_MDF_UNKNOWN (unknown)
  Speed: Unknown
  Configured Speed: Unknown
  Device Locator: P1-DIMMD1
  Bank Locator: P0_Node1_Channel0_Dimm0
  Minimum Voltage: 1.20V
  Maximum Voltage: 1.20V
  Configured Voltage: 1.20V

Блоки начинаются с ID SIZE TYPEзаголовка и заканчиваются информацией о сконфигурированном напряжении. Команда выводит один из этих блоков данных для каждого DIMM, разделенных одной пустой строкой каждый.


Я хотел бы иметь возможность получить блок информации для определенного слота DIMM на основе поля Location Tag, но не уверен, как это сделать. Я почти уверен, что это можно сделать, awkно знаю только, как напечатать совпадение awk '/P1-DIMMD1/'или строку перед совпадениемawk '/P1-DIMMD1/ {print a}{a=$0}'

Кто-нибудь знает, как мне извлечь весь этот блок данных, если он Location Tagсоответствует моему поиску ( P1-DIMMD1)?

решение1

Следующее будет соответствовать тегу, указанному в переменной тега:

awk -v tag=P1-DIMMD1 '/ID    SIZE TYPE/ { block = $0; output = 0; next } { block = block "\n" $0 } /Location Tag/ { output = ($0 ~ tag) } /Configured Voltage/ && output { print block }'

Скрипт AWK — это

/ID    SIZE TYPE/ {
  block = $0
  output = 0
  next
}

{ block = block "\n" $0 }

/Location Tag/ { output = ($0 ~ tag) }

/Configured Voltage/ && output { print block }

Мы накапливаем блок в blockпеременной и выводим его по достижении конца блока, если в процессе мы увидели нужный тег.

решение2

Вы могли быиспользовать ed...иуспокойся, мужик!

Вы должныхотетьОднако для этого лучше использовать ed, поскольку ed хочет работать с файлом, а не как с частью конвейера.

  1. command > dimm-output
  2. wanted=P1-DIMMD1
  3. ed -s dimm-output <<< $'/Location Tag: '"$wanted"$'\n?^ID.*SIZE.*TYPE\n.,/Configured Voltage/p\nq\n' | sed 1,2d

Командная edстрока разбивается на четыре \nкоманды, разделенные символом -:

  1. поиск вперед, используя /, для текста "Location Tag: ", за которым следует значение $wantedпеременной
  2. поиск в обратном направлении, используя ?, для шаблона: (начало строки), "ID", что угодно, "РАЗМЕР", что угодно, "ТИП"
  3. от этой строки ( .), до ( ,) следующей строки, которая соответствует «Настроенному напряжению», вывести эти строки ( p)
  4. бросил ed:q

Поскольку ed автоматически выводит совпадающую строку при поиске, я использовал sedэтот способ, чтобы удалить эти две строки.

решение3

Вдохновленный замечательным ответом @Stephen Kitts, я написал немного более общий скрипт для выполнения сопоставления блоков при наличии указанного шаблона начала и конца.

#!/usr/bin/awk -f
BEGIN {
    pstart=ARGV[1];
    pstop=ARGV[2];
    pmatch=ARGV[3];
    ARGV[1]=ARGV[4];
    ARGC=2;
}
$0 ~ pstart { block = $0; output = 0; next }
{ block = block "\n" $0 }
$0 ~ pmatch { output = 1 }
$0 ~ pstop && output { print block; output = 0 }

Использование:match_block START END MATCH [FILE]

./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1' f

или

command | ./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1'

Спасибо за предложение написать это как awkскрипт напрямую. Мой оригинальный скрипт оболочки был:

#!/bin/sh

[ -z "$4" ] && file="-" || file="$4"

awk \
  -v BLOCKSTART_PATTERN="$1" \
  -v BLOCKEND_PATTERN="$2" \
  -v BLOCKMATCH_PATTERN="$3" \
  '
  $0 ~ BLOCKSTART_PATTERN { block = $0; output = 0; next }
  { block = block "\n" $0 }
  $0 ~ BLOCKMATCH_PATTERN { output = 1 }
  $0 ~ BLOCKEND_PATTERN && output { print block; output = 0 }
  ' "$file"

Использование: match_block START END MATCH [FILE].
Если файл не указан, stdinбудет использован.

В твоем случае:

command | ./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1'

или

./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1' file

Связанный контент