Extract multiple lines if match
The following will match the tag given in the tag variable:
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 }'
The AWK script is
/ID SIZE TYPE/ {
block = $0
output = 0
next
}
{ block = block "\n" $0 }
/Location Tag/ { output = ($0 ~ tag) }
/Configured Voltage/ && output { print block }
We accumulate a block in the block
variable, and output it when we reach the end of the block if we saw the right tag in the process.
You could use ed ... and sed, man!
You have to want to use ed for this one, though, as ed wants to operate on a file, not as part of a pipeline.
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
The ed
command-string breaks down to four \n
-separated commands:
- search forwards, using
/
, for the text "Location Tag: " followed by the value of the$wanted
variable - search backwards, using
?
, for the pattern: (start-of-line), "ID", anything, "SIZE", anything, "TYPE" - from that line (
.
), through (,
) the next line that matches "Configured Voltage", print those lines (p
) - quit ed:
q
Because ed auto-prints the matching line when you search, I used sed
here to delete those two lines.
Inspired by @Stephen Kitts great answer, I wrote a little more general script to perform block matching when having a specified start and end pattern.
#!/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 }
Usage: match_block START END MATCH [FILE]
./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1' f
or
command | ./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1'
Thanks for suggesting writing this as an awk
script directly. My original shell script was:
#!/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"
Usage: match_block START END MATCH [FILE]
.
If file is omitted, stdin
will be used.
In your case:
command | ./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1'
or
./match_block '^ID' 'Configured Voltage' 'Location Tag: P1-DIMMD1' file