Sed

sed/awk/perl:反轉逗號分隔值的順序,保留其他文本

  • October 19, 2014

我有這段文字:

LABEL1
   .BYTE 01, 02, 03, 04, 05
   .BYTE 01, 02, 03

我只需要反轉逗號分隔值的順序:

LABEL1
   .BYTE 05, 04, 03, 02, 01
   .BYTE 03, 02, 01

我需要這樣的事情:

ITINERARY_ARRAY_01
   .BYTE <ITINERARY_00A
   .BYTE <ITINERARY_01A
   .BYTE <ITINERARY_02A
   .BYTE <ITINERARY_03A
   .BYTE <ITINERARY_04A
   .BYTE <ITINERARY_05A
   .BYTE <ITINERARY_06A
   .BYTE <ITINERARY_07A
   .BYTE <ITINERARY_08A
   .BYTE <ITINERARY_09A
   .BYTE <ITINERARY_10A
   .BYTE <ITINERARY_11A
   .BYTE <ITINERARY_12A
   .BYTE <ITINERARY_13A
   .BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
   .BYTE $03, $05, $07, $00
;-------------------
ITINERARY_01F
   .BYTE $03, $05, $07, $09, $00
;-------------------
ITINERARY_01G
   .BYTE $28, $0D, $00
;-------------------
ITINERARY_01H
   .BYTE $28, $0D, $0F, $13, $00
;-------------------
ITINERARY_01I
   .BYTE $28, $0D, $0F, $11, $00
;-------------------
ITINERARY_01J
   .BYTE $03, $05, $07, $09, $20, $1E, $00
;-------------------
ITINERARY_01K
   .BYTE $28, $0D, $0F, $13, $15, $00
;-------------------
ITINERARY_01L
   .BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
   .BYTE $00
;---------------------

除了“.BYTE”之後的值,什麼都不需要改變,必須是相反的順序,十六進制格式,使用“$”作為前綴……對不起這個“編輯”,但我現在才看到這個。再次感謝 !

文件revbytes2.awk

#!/usr/bin/awk -f
BEGIN {
       FS=",? +"
}
NF>2 && match($0,"^ +\.BYTE ") {
       printf substr($0,1,RSTART+RLENGTH-1)
       for(i=NF;i>3;i--) printf $i", "
       print $3
       next
}
1

FS=",? +"使得將字節之間的空格和加號空格序列awk辨識為欄位分隔符。.BYTE``,

對於每一行,這將查找具有超過 2 個欄位的行,以空格開頭,後跟.BYTE一個空格,並將此前綴的開頭和長度記RSTART入表達式RLENGTH的副作用中match(...)

如果找到此匹配項並且有超過 2 個欄位,則使用RSTARTand將前綴從原始行中刪除,RLENGTH然後以相反的順序列印剩餘的欄位。

如果.BYTE未找到空格加空格前綴或不超過 2 個欄位,則將按原樣列印該行。所以這也將針對.BYTE只定義一個字節的 -line 完成,因為沒有什麼可以反轉的。

測試執行:

$ diff -u$(wc -l <input) input <(awk -f revbytes2.awk input)
--- input       2014-10-19 06:04:48.280714146 +0200
+++ /dev/fd/63  2014-10-19 22:40:01.385538235 +0200
@@ -1,42 +1,42 @@
ITINERARY_ARRAY_01
    .BYTE <ITINERARY_00A
    .BYTE <ITINERARY_01A
    .BYTE <ITINERARY_02A
    .BYTE <ITINERARY_03A
    .BYTE <ITINERARY_04A
    .BYTE <ITINERARY_05A
    .BYTE <ITINERARY_06A
    .BYTE <ITINERARY_07A
    .BYTE <ITINERARY_08A
    .BYTE <ITINERARY_09A
    .BYTE <ITINERARY_10A
    .BYTE <ITINERARY_11A
    .BYTE <ITINERARY_12A
    .BYTE <ITINERARY_13A
    .BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
-    .BYTE $03, $05, $07, $00
+    .BYTE $00, $07, $05, $03
;-------------------
ITINERARY_01F
-    .BYTE $03, $05, $07, $09, $00
+    .BYTE $00, $09, $07, $05, $03
;-------------------
ITINERARY_01G
-    .BYTE $28, $0D, $00
+    .BYTE $00, $0D, $28
;-------------------
ITINERARY_01H
-    .BYTE $28, $0D, $0F, $13, $00
+    .BYTE $00, $13, $0F, $0D, $28
;-------------------
ITINERARY_01I
-    .BYTE $28, $0D, $0F, $11, $00
+    .BYTE $00, $11, $0F, $0D, $28
;-------------------
ITINERARY_01J
-    .BYTE $03, $05, $07, $09, $20, $1E, $00
+    .BYTE $00, $1E, $20, $09, $07, $05, $03
;-------------------
ITINERARY_01K
-    .BYTE $28, $0D, $0F, $13, $15, $00
+    .BYTE $00, $15, $13, $0F, $0D, $28
;-------------------
ITINERARY_01L
-    .BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
+    .BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
    .BYTE $00
;---------------------

比較mawkgawk輸出:

$ diff <(mawk -f revbytes2.awk input) <(gawk -f revbytes2.awk input)
gawk: revbytes2.awk:5: warning: escape sequence `\.' treated as plain `.'

顯然在標準輸出上沒有區別。好的!

如果您寫"^ +\056BYTE "而不是"^ +\.BYTE "match(...)表達式內部,警告就會消失。

也許gawk經常使用的人知道避免警告的更好方法。

在這裡,我這樣做sed

sed '/,/!b                                                   
s/\( *[^ ]*\)\(.*\)/\2,\n\1/;:t
s/\([^,]*,\)\(\n.*\)/\2\1/;tt
s/\n\(.*\),/\1/' <<\DATA
LABEL1
   .BYTE 01, 02, 03, 04, 05
   .BYTE 01, 02, 03        
LABEL1
   .BYTE 01, 02, 03, 04, 05
   .BYTE 01, 02, 03
DATA

輸出

LABEL1
   .BYTE 05, 04, 03, 02, 01 
   .BYTE 03, 02, 01 
LABEL1
   .BYTE 05, 04, 03, 02, 01 
   .BYTE 03, 02, 01 

它檢查目前行上的逗號。如果!沒有逗號,則sed b退出腳本並自動列印該行。如果該行包含逗號,sed執行以下操作:

  1. 它首先通過s///替換以下內容來準備行:
  • \( *[^ ]*\)- 第一個出現的零個或多個空格序列,緊隨其後的是一系列零個或多個非空格字元,引用為\1緊隨其後的是…
  • \(.*\)- 行中的其他所有內容都引用為\2
  • …和\2,\n\1
  • 注意-像這樣\n在右側s///替換欄位中使用轉義符不是完全可移植的。對於sed不支持它的 a ,可以通過用文字換行符代替n語句中的 the 來完成。
  1. :定義了一個名為 的分支/測試標籤t
  2. 雖然它仍然可以,但可以sed s///替代:
  • \([^,]*,\)- 零個或多個非逗號字元的序列,然後引用單個逗號,\1緊隨其後的是…
  • \(\n.*\)- 以至少一個\newline 字元開頭的序列,後跟模式空間中剩餘的任何內容/所有內容,引用為\2
  • …與\2\1.
  1. 如果先前的s///替換estt成功,sed則分支回到:test 標籤並再次嘗試。
  2. 最後sed做了一些清理並替換:
  • \n\(.*\),- 第一個出現的\newline 字元和最後一個出現的逗號…
  • \1- …與所有介於兩者之間的東西。

sed遞歸替換一樣,\newline 分隔符一次向後走一個逗號分隔的欄位。\n當ewline 是該行的第一個字元時,它會停止替換。這是l通過遞歸替換過程的進展:

01, 02, 03, 04, 05,\n    .BYTE$
01, 02, 03, 04,\n    .BYTE 05,$
01, 02, 03,\n    .BYTE 05, 04,$
01, 02,\n    .BYTE 05, 04, 03,$
01,\n    .BYTE 05, 04, 03, 02,$
\n    .BYTE 05, 04, 03, 02, 01,$

在其最初的預備替換之後,除了逗號和插入的換行符之外,sed不分隔任何內容。\n因此,任何類型的逗號分隔值都可以正常工作。這是通過它執行長時間的輸出:

ITINERARY_ARRAY_01
   .BYTE <ITINERARY_00A
   .BYTE <ITINERARY_01A
   .BYTE <ITINERARY_02A
   .BYTE <ITINERARY_03A
   .BYTE <ITINERARY_04A
   .BYTE <ITINERARY_05A
   .BYTE <ITINERARY_06A
   .BYTE <ITINERARY_07A
   .BYTE <ITINERARY_08A
   .BYTE <ITINERARY_09A
   .BYTE <ITINERARY_10A
   .BYTE <ITINERARY_11A
   .BYTE <ITINERARY_12A
   .BYTE <ITINERARY_13A
   .BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
   .BYTE $00, $07, $05, $03 
;-------------------
ITINERARY_01F
   .BYTE $00, $09, $07, $05, $03 
;-------------------
ITINERARY_01G
   .BYTE $00, $0D, $28 
;-------------------
ITINERARY_01H
   .BYTE $00, $13, $0F, $0D, $28 
;-------------------
ITINERARY_01I
   .BYTE $00, $11, $0F, $0D, $28 
;-------------------
ITINERARY_01J
   .BYTE $00, $1E, $20, $09, $07, $05, $03 
;-------------------
ITINERARY_01K
   .BYTE $00, $15, $13, $0F, $0D, $28 
;-------------------
ITINERARY_01L
   .BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
   .BYTE $00
;---------------------

引用自:https://unix.stackexchange.com/questions/162826