Bei Übereinstimmung mehrere Zeilen extrahieren

Bei Übereinstimmung mehrere Zeilen extrahieren

Ich habe einen Befehl, der Informationen zu allen DIMM-Steckplätzen in Blöcken wie den folgenden ausgibt:

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

Die Blöcke beginnen mit dem ID SIZE TYPEHeader und enden mit den konfigurierten Spannungsinformationen. Der Befehl gibt für jedes DIMM einen dieser Datenblöcke aus, jeweils durch eine einzelne Leerzeile getrennt.


Ich möchte den Informationsblock für einen bestimmten DIMM-Steckplatz basierend auf dem Location TagFeld abrufen können, bin mir aber nicht sicher, wie ich das anstellen soll. Ich bin ziemlich sicher, dass dies mit möglich ist, weiß aber nur, wie man die Übereinstimmung oder die Zeile vor der Übereinstimmung awkdrucktawk '/P1-DIMMD1/'awk '/P1-DIMMD1/ {print a}{a=$0}'

Weiß jemand, wie ich diesen ganzen Datenblock extrahieren kann, wenn er Location Tagmeiner Suche entspricht ( P1-DIMMD1)?

Antwort1

Folgendes stimmt mit dem in der Tag-Variable angegebenen Tag überein:

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 }'

Das AWK-Skript ist

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

{ block = block "\n" $0 }

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

/Configured Voltage/ && output { print block }

Wir sammeln einen Block in der blockVariable und geben ihn aus, wenn wir das Ende des Blocks erreichen, sofern wir dabei das richtige Tag gesehen haben.

Antwort2

Sie könntenverwenden ed...Undsed, Mann!

Du musstwollenEs empfiehlt sich jedoch, hierfür ed zu verwenden, da ed mit einer Datei arbeiten möchte und nicht als Teil einer Pipeline.

  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

Die edBefehlszeichenfolge gliedert sich in vier \ndurch -getrennte Befehle:

  1. Suche vorwärts mit /nach dem Text "Location Tag: " gefolgt vom Wert der $wantedVariablen
  2. Suche rückwärts, mit ?, nach dem Muster: (Zeilenanfang), „ID“, beliebig, „GRÖSSE“, beliebig, „TYP“
  3. Von dieser Zeile ( .) bis ( ,) zur nächsten Zeile, die mit „Konfigurierte Spannung“ übereinstimmt, drucken Sie diese Zeilen ( p)
  4. beendet:q

Da ed beim Suchen automatisch die passende Zeile ausgibt, habe ich sedhier verwendet, um diese beiden Zeilen zu löschen.

Antwort3

Inspiriert von der tollen Antwort von @Stephen Kitts habe ich ein etwas allgemeineres Skript geschrieben, um Blockabgleiche durchzuführen, wenn ein bestimmtes Start- und Endmuster vorliegt.

#!/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 }

Verwendung:match_block START END MATCH [FILE]

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

oder

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

Vielen Dank für den Vorschlag, dies direkt als awkSkript zu schreiben. Mein ursprüngliches Shell-Skript war:

#!/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"

Verwendung: match_block START END MATCH [FILE]Wenn
die Datei weggelassen wird, stdinwird verwendet.

In Ihrem Fall:

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

oder

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

verwandte Informationen