一致する場合は複数行を抽出

一致する場合は複数行を抽出

次のように、すべての 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 ごとにこれらのデータ ブロックの 1 つを、それぞれ 1 つの空白行で区切って出力します。


フィールドに基づいて特定の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文字列は、 で区切られた 4 つのコマンドに分割されます\n

  1. を使って前方検索し、/テキスト「Location Tag:」の後に$wanted変数の値が続くものを検索する。
  2. , を使用して、パターンを後方に検索します?: (行頭)、"ID"、任意の文字、"SIZE"、任意の文字、"TYPE"
  3. その行(.)から,「設定された電圧」に一致する次の行( )まで、それらの行を印刷します(p
  4. 終了 ed:q

ed は検索時に一致する行を自動的に印刷するため、sedここではそれらの 2 行を削除しました。

答え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

関連情報