我正在嘗試使用 bash 腳本對文件進行一些文字處理。目標是取得在「attribute:」標籤下縮排的所有以「field:」開頭的行,並將它們與後面以「- attr:」開頭的關聯行交換。
到目前為止,我認為我的正規表示式模式應該與標籤相符:
/ *field:(.*)/g
/ *- attr:(.*)/g
但我在解析所需字段並讓它們正確交換的邏輯方面還沒有任何成功。
輸入文字範例
- metric: 'example.metric.1'
attributes:
field: 'example 1'
- attr: 'example1'
field: 'example 2'
- attr: 'example2'
field: 'example 3'
- attr: 'example3'
field: 'example 4'
- attr: 'example4'
- metric: 'example.metric.2'
attributes:
field: 'example 5'
- attr: 'example5'
field: 'example 6'
- attr: 'example6'
field: 'example 7'
- attr: 'example7'
- metric: 'example.metric.3'
...
所需輸出
- metric: 'example.metric.1'
attributes:
- attr: 'example1'
field: 'example 1'
- attr: 'example2'
field: 'example 2'
- attr: 'example3'
field: 'example 3'
- attr: 'example4'
field: 'example 4'
- metric: 'example.metric.2'
attributes:
- attr: 'example5'
field: 'example 5'
- attr: 'example6'
field: 'example 6'
- attr: 'example7'
field: 'example 7'
- metric: 'example.metric.3'
...
我將如何實現這個目標?
答案1
在每個 Unix 機器上的任何 shell 中使用任何 awk:
$ awk '$1=="field:"{s=ORS $0; next} {print $0 s; s=""}' file
- metric: 'example.metric.1'
attributes:
- attr: 'example1'
field: 'example 1'
- attr: 'example2'
field: 'example 2'
- attr: 'example3'
field: 'example 3'
- attr: 'example4'
field: 'example 4'
- metric: 'example.metric.2'
attributes:
- attr: 'example5'
field: 'example 5'
- attr: 'example6'
field: 'example 6'
- attr: 'example7'
field: 'example 7'
- metric: 'example.metric.3'
如果您在某些行後可能沒有空格field:
,或者出於某種原因迫切希望使用正則表達式,則更改為$1=="field:"
或$1~/^field:/
,/^[[:space:]]*field:/
無論您喜歡哪一個。
答案2
和sed
:
sed -n '/^ *field: /{h;n;G};p' data
如果我們匹配一個field
關鍵字,那麼:
- 將目前行保存在
hold space
(h
)中 pattern space
從(n
)中的文件中取得下一行- 將
pattern space
與hold space
(G
) 交換(相當於換行)
列印您遇到的每一行:p
答案3
使用awk
:
awk '{if ($1 == "field:") {a=$0;x=0}
else if (/- attr:/) {$0 = $0 ORS a; x=1} else {x=1}}x' input
在此命令中,如果field:
找到,則將目前輸入 record( $0
) 儲存到變數中a
,並將 x 設為零。如果attr:
找到,$0
則將 d 變更為 old ,$0
然後ORS
(newline) ,然後是變數a
。
答案4
我們可以使用 POSIX sed 結構來翻轉上述行。
sed '/attr:/!x;$G' file