最近做了一個文本 CDR 轉換器,從 A 樣式轉換爲 B 樣式,如下所示。
A 樣式
B 樣式
A 樣式到 B 樣式的轉換要點如下:
1. header 和 trailer 都可直接轉換,但是 B 樣式需要加上 CDR 的計數
2. B 樣式的 header 還含有 record type ,需要從 A 樣式的某個註釋行中獲取
3. 字段域的轉換比較簡單,都是一行對一行
4. A 樣式有註釋行,轉換時要全部刪除
轉換由 awk 和 sed 完成,完整的命令是這樣的:
awk 'BEGIN { cnt=0; } { if ( $0 == "RECORD" ) { cnt++; printf("Record (%d)/n", cnt); } else if ( $0 == "." ) { printf("End of Record (%d)/n", cnt); } else { print $0; } }' layout_a | sed '/^Record/{N;N;N;s//n//g;}' | sed 's/^/(Record (.*)/).*input_type /(.*/)$//1 "/2"/;s/^F /(.*/) /(.*/)$/ "/1" = "/2"/;/^#/d' > layout b
具體解析如下:
1. awk 'BEGIN { cnt=0; } { if ( $0 == "RECORD" ) { cnt++; printf("Record (%d)/n", cnt); } else if ( $0 == "." ) { printf("End of Record (%d)/n", cnt); } else { print $0; } }' layout_a | sed '/^Record/{N;N;N;s//n//g;}' | sed 's/^/(Record (.*)/).*input_type /(.*/)$//1 "/2"/;s/^F /(.*/) /(.*/)$/ "/1" = "/2"/;/^#/d' > layout b
判斷 CDR 的 header 和 trailer 。如果是 header ,即該行內容爲 ”RECORD” ,計數器加一,且輸出 ”Record (?)” 到下一步;如果是 trailer ,即該行內容爲 ”.” ,輸出 ”End of Record (?)” 到下一步;否則,不作修改輸出到下一步。
2. awk 'BEGIN { cnt=0; } { if ( $0 == "RECORD" ) { cnt++; printf("Record (%d)/n", cnt); } else if ( $0 == "." ) { printf("End of Record (%d)/n", cnt); } else { print $0; } }' layout_a | sed '/^Record/{N;N;N;s//n//g;}' | sed 's/^/(Record (.*)/).*input_type /(.*/)$//1 "/2"/;s/^F /(.*/) /(.*/)$/ "/1" = "/2"/;/^#/d' > layout b
遇到 header ,合併後續三行。因爲第四行保留了該 CDR 的 Record type 。
3. awk 'BEGIN { cnt=0; } { if ( $0 == "RECORD" ) { cnt++; printf("Record (%d)/n", cnt); } else if ( $0 == "." ) { printf("End of Record (%d)/n", cnt); } else { print $0; } }' layout_a | sed '/^Record/{N;N;N;s//n//g;}' | sed ' s/^/(Record (.*)/).*input_type /(.*/)$//1 "/2"/ ; s/^F /(.*/) /(.*/)$/ "/1" = "/2"/;/^#/d' > layout b
從上一步生成的 header 提取合適的內容,形成 B 樣式的 header 。注意括號的運用。
4. awk 'BEGIN { cnt=0; } { if ( $0 == "RECORD" ) { cnt++; printf("Record (%d)/n", cnt); } else if ( $0 == "." ) { printf("End of Record (%d)/n", cnt); } else { print $0; } }' layout_a | sed '/^Record/{N;N;N;s//n//g;}' | sed 's/^/(Record (.*)/).*input_type /(.*/)$//1 "/2"/; s/^F /(.*/) /(.*/)$/ "/1" = "/2"/; /^#/d' > layout b
提取各個字段的鍵和值,並加上雙引號,形成 B 樣式的字段域。同樣注意括號的運用。
5. awk 'BEGIN { cnt=0; } { if ( $0 == "RECORD" ) { cnt++; printf("Record (%d)/n", cnt); } else if ( $0 == "." ) { printf("End of Record (%d)/n", cnt); } else { print $0; } }' layout_a | sed '/^Record/{N;N;N;s//n//g;}' | sed 's/^/(Record (.*)/).*input_type /(.*/)$//1 "/2"/;s/^F /(.*/) /(.*/)$/ "/1" = "/2"/; /^#/d ' > layout b
刪除剩餘的註釋行。