現網中經常遇到匹配到某一關鍵字下的所有行合并到同一行,再次匹配到相關關鍵字再和下面的合并,樣本如下:
# line1
a
b
# line2
c
d
e
# line3
f
想要變成:
# line1 a b
# line2 c d e
# line3 f
即:把某個"# line"打頭與下一個"#line"打頭之間的行合成一行(這一行包括#line),但兩個#line之間的行數是不確定的。
以下是發動群眾從群裡得到的解決方案(分別為sed和awk實現):
# sed實現方法
# sed -n '/#/{:a;N;/\n#/{P;D};s/\n//;$p;ta}' file
# sed ':a;$!N;/\n#$/!s/\n//;ta;s/#/\n#/g' file
# sed -n '1h;/#/!{1!H;$!b};1!{x;s/\n//g;p}' file
# awk實現方法
# awk '{printf (/10/&&NR>1)?"\n"$0:$0}' file
# awk '/^#10/{if (n++) print ""}{printf $0}' file
# awk 'BEGIN{FS="\n";ORS=""};{if($0 ~ /^10/ && NR>1){print "\n"$0;}else{print}}' file
個人還是偏向於使用awk 方法,而且理解上也比較容易理解,sed方法理解起來感覺想當費勁。
現網需求如下:通過BMC自動化採集工具,採到當前現網某機房掛載某NAS儲存的所有主機。通過grep匹配NAS機頭IP,有結果輸出的證明有掛載,無輸出的表明當前未掛載該NAS,輸出類似如下圖
由於該機房有上千台左右的主機,輸出結果還是比較多的。所以想將每台主機的結果主機名稱等合并到同一行,並通過二次匹配擷取所有掛載的主機,這樣比較方便匯入excel中展示出來。
# awk '/^10/{if (n++) print ""}{printf $0}' caiji.txt |awk '{if($NF!="###"){print $0}}'
由於所有IP都是以10開頭的,這裡先正則匹配所有10開頭的行,如果匹配不上的,通過printf列印並繼續向下匹配,匹配上的通過print實現換行。後面的二次匹配就不解釋了,比較簡單。
註:printf 與 print的區別是printf列印的時候是不會換行的,print列印後,預設是帶有\n換行的。如果只列印一行的話,printf + \n = print。