如果匹配則提取多行

如果匹配則提取多行

我有一個命令可以輸出有關區塊中所有 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 輸出這些資料塊之一,每個資料塊之間由一個空白行分隔。


我希望能夠根據該Location Tag字段獲取特定 DIMM 插槽的資訊塊,但我不確定如何進行。我很確定這可以完成,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

你可以使用edsed,夥計!

你必須不過,要使用 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. 使用 向前搜尋文字“位置標記:”,後面跟著變/數值$wanted
  2. 使用 , 向後搜尋?模式:(行首)、“ID”、任何內容、“SIZE”、任何內容、“TYPE”
  3. 從該行 ( .) 到 ( ,) 與「配置電壓」相符的下一行,列印這些行 ( p)
  4. 退出編輯: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直接將其編寫為腳本。我原來的 shell 腳本是:

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

相關內容