使用awk如何将固定宽度的多行记录转换为单行记录
我想将固定宽度的文件多行记录转换为单行记录。该文件包含使用awk如何将固定宽度的多行记录转换为单行记录,awk,Awk,我想将固定宽度的文件多行记录转换为单行记录。该文件包含4个字段: 日期戳,严重性,错误代码,消息类型根据字段中的数据,记录数据可以跨越多行。例如 日期戳字段宽度为10个字符-但数据值为19个字符,因此它跨越两行。前10个字符在第一行,后9个字符在第二行 字段位置 日期戳=1-10 severity=12-17[这些值可能是错误、信息、警告,因此如果该值是警告,则剩余数据将放在12-17的第二行中] 错误代码=18-25 消息=26-70 记录之间没有空行 2014-02-21 INFO UTF8
4个字段
:
日期戳
,严重性
,错误代码
,消息类型
根据字段中的数据,记录数据可以跨越多行。例如
日期戳
字段宽度为10个
字符-但数据值为19个
字符,因此它跨越两行。前10个字符在第一行,后9个字符在第二行
字段位置
日期戳=1-10
severity=12-17[这些值可能是错误、信息、警告,因此如果该值是警告,则剩余数据将放在12-17的第二行中]
错误代码=18-25
消息=26-70
记录之间没有空行
2014-02-21 INFO UTF8_INT Starting execution of workflow
07:01:59 [wf_router] in domain.
2014-02-21 error UTF8_INT SQ_ff:Exchange: Rowdata: ( RowType=0
07:01:59 (insert) Src Rowid=1 TargIELD:Char.500:):
".Improved By Resting
[[<~a~>Resting<~a0~>]]|Lying Down
[[<FNT><!>no Lying Down]]).
2014-02-21 warni UTF8_INT SQ_ff:Exchange: Rowdata: ( RowType=0
ng (insert) Src Rowid=1 TargIELD:Char.500:):
".Improved By Resting
[[<~a~>Resting<~a0~>]]|Lying Down
[[<FNT><!>no Lying Down]]).
虽然awk设计用于使用字段分隔符(默认情况下为空白),但awk也可以读取固定宽度的文件。要检索宽度为w的字段,从p列开始(其中1是行中最左侧的位置),请使用
substr($0,p,w)
。要跨行累积列数据,只需在每列中使用一个变量即可
{
if (/[^ \t]/) {
datetime = datetime " " trim(substr($0, 1, 10));
severity = severity substr($0, 12, 5);
errorcode = errorcode substr($0, 18, 8);
message = message " " trim(substr($0, 26));
}
else {
output();
datetime = severity = errorcode = message = "";
}
}
END {
output();
}
function output() {
if (datetime || severity || errorcode || message) {
print trim(datetime) " ; " trim(severity) " ; " trim(errorcode) " ; " trim(message);
}
}
function trim(s) {
gsub(/^[ \t]+|[ \t]+$/, "", s);
return s;
}
输入(注意我在第1行对UTF8\u INT
的对齐进行了消毒):
输出:
2014-02-21 07:01:59 ; INFO ; UTF8_INT ; Starting execution of workflow [wf_router] in domain.
2014-02-21 07:01:59 ; error ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
2014-02-21 ; warning ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
注:
- 由于您没有回答我的所有问题,我无法知道脚本是否符合您的所有要求
- 假设在输出数据中需要分号作为字段分隔符,我想知道如何处理输入数据中已经存在的分号。我应该采取某种逃避方式吗
- 您需要这样的东西(使用GNU awk进行各种扩展):
$cat tst.awk
开始{FIELDWIDTHS=“10 1 5 1 8 45”}
/^[0-9]{4}(-0-9]{2}{2}/&(NR>1){prtrec()}
{
对于(i=1;iWhy是UTF8\u INT
在第1行中未对齐的,这是打字错误吗?为什么warning
在第17列中没有第一个“n”(您的规范状态为12-17,但这更像是12-16)?“记录之间没有空行”,您如何判断记录的结束位置?或者我误解了您对“中间”一词的解释?最后但并非最不重要的是,所需的输出是什么?我输入了一些示例数据只是为了显示记录。我想将此数据转换为单行记录格式,2014-02-21 07:01:59;INFO;UTF8_INT;开始执行工作流[wf_router]在域中。你能解释一下函数prtrec()的逻辑吗?{n=split(“1 3 5 6”,f)for(i=1;i你认为它是什么,我来填补空白?非常感谢你的快速回复。你的两个逻辑都是正确的
2014-02-21 07:01:59 ; INFO ; UTF8_INT ; Starting execution of workflow [wf_router] in domain.
2014-02-21 07:01:59 ; error ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
2014-02-21 ; warning ; UTF8_INT ; SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting [[<~a~>Resting<~a0~>]]|Lying Down [[<FNT><!>no Lying Down]]).
$ cat tst.awk
BEGIN { FIELDWIDTHS="10 1 5 1 8 45" }
/^[0-9]{4}(-[0-9]{2}){2}/ && (NR>1) { prtrec() }
{
for (i=1;i<=NF;i++) {
rec[i] = rec[i] $i
}
}
END { prtrec() }
function prtrec() {
n=split("1 3 5 6",f)
for (i=1;i<=n;i++) {
gsub(/^\s+|\s+$/,"",rec[f[i]])
printf "%s%s", rec[f[i]], (i<n?OFS:ORS)
}
delete rec
}
$ gawk -f tst.awk file
2014-02-2107:01:59 INFO UTF8_INT Starting execution of workflow [wf_router] in domain.
2014-02-2107:01:59 error UTF8_INT SQ_ff:Exchange: Rowdata: ( RowType=0(insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting[[<~a~>Resting<~a0~>]]|Lying Down[[<FNT><!>no Lying Down]]).
2014-02-21 warning UTF8_INT SQ_ff:Exchange: Rowdata: ( RowType=0 (insert) Src Rowid=1 TargIELD:Char.500:): ".Improved By Resting[[<~a~>Resting<~a0~>]]|Lying Down[[<FNT><!>no Lying Down]]).