awk - 处理带有标题、子标题和记录的文件

awk - 处理带有标题、子标题和记录的文件

我有一个具有以下格式的数据文件:

Header:H1
Sub-header:H1S1
Record:R1
Record:R2
Sub-header:H1S2
Record:R5
Record:R6
Sub-header:H1S3
Record:R9
Record:R10
Header:H2
Sub-header:H2S1
Record:R15
Record:R16
Header:H3
Sub-header:H3S1
Record:R25
Record:R26
Sub-header:H3S2
Record:R30
Record:R31

我想使用 AWK 处理此文件,使文件具有以下格式:

H1, H1S1, R1
H1, H1S1, R2
H1, H1S2, R5
H1, H1S2, R6
H1, H1S3, R9
H1, H1S3, R10
H2, H2S1, R15
H2, H2S1, R16
H3, H3S1, R25
H3, H3S1, R26
H3, H3S2, R30
H3, H3S2, R31

怎么做?

答案1

当您看到标题和副标题时,您需要记住它们,然后当您看到 Record: 行时打印它们(连同记录数据)。

$ awk -F: -v OFS=", " '/^Header:/     { header    = $2; next };
                       /^Sub-header:/ { subheader = $2; next };
                       /^Record:/     { print header, subheader, $2 }' input.txt 
H1, H1S1, R1
H1, H1S1, R2
H1, H1S2, R5
H1, H1S2, R6
H1, H1S3, R9
H1, H1S3, R10
H2, H2S1, R15
H2, H2S1, R16
H3, H3S1, R25
H3, H3S1, R26
H3, H3S2, R30
H3, H3S2, R31

这些next语句是一个小的优化 - 因为我们不需要一旦我们从中提取了 $2,就跳到下一行输入并从脚本顶部再次开始处理。

对于这样的脚本,它对性能的影响很小(如果有的话)——它的作用并不大。对于更复杂的脚本,可能需要匹配大量模式或进行计算,这可能会产生重大影响。

答案2

:假设输入文件中的 周围没有空格,以下awk程序将执行该任务:

awk 'BEGIN{FS=":";OFS=","} $1=="Header"{h=$2} $1=="Sub-header"{s=$2} $1=="Record" {print h,s,$2}' input.txt

这将首先设置:为输入的字段分隔符,并,设置为输出的字段分隔符。

然后,每次第一个输入字段分别被命名为 和时,它将分别读取将最新的标头和子标头存储在变量h和中。如果遇到一行,它将打印字段值以及分别存储在和中的值。sHeaderSub-headerRecordhs

Sub-header请注意,这假设第一个 之前始终有 a Record。如果您想允许空子标题,请将第一个规则块从

$1=="Header"{h=$2}

$1=="Header"{h=$2;s=""}

答案3

每当您的输入中有标记值对时,我发现最好首先创建一个数组来存储该映射(f[]如下),然后您可以通过按值寻址来访问/打印/比较/修改/任何值标签(名称):

$ cat tst.awk
BEGIN { FS=":"; OFS=", " }
{ f[$1] = $2 }
/^Record/ { print f["Header"], f["Sub-header"], $2 }

$ awk -f tst.awk file
H1, H1S1, R1
H1, H1S1, R2
H1, H1S2, R5
H1, H1S2, R6
H1, H1S3, R9
H1, H1S3, R10
H2, H2S1, R15
H2, H2S1, R16
H3, H3S1, R25
H3, H3S1, R26
H3, H3S2, R30
H3, H3S2, R31

相关内容