
У меня есть команда, которая выводит информацию обо всех слотах 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 хочет работать с файлом, а не как с частью конвейера.
command > dimm-output
wanted=P1-DIMMD1
ed -s dimm-output <<< $'/Location Tag: '"$wanted"$'\n?^ID.*SIZE.*TYPE\n.,/Configured Voltage/p\nq\n' | sed 1,2d
Командная ed
строка разбивается на четыре \n
команды, разделенные символом -:
- поиск вперед, используя
/
, для текста "Location Tag: ", за которым следует значение$wanted
переменной - поиск в обратном направлении, используя
?
, для шаблона: (начало строки), "ID", что угодно, "РАЗМЕР", что угодно, "ТИП" - от этой строки (
.
), до (,
) следующей строки, которая соответствует «Настроенному напряжению», вывести эти строки (p
) - бросил 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