繁体   English   中英

使用多个 header 行拆分文件

[英]Splitting a File with multiple header line

我正在尝试使用以下代码拆分具有多个 header 行的大文件。 虽然在工作; 但是在拆分文件中的 header 之后引入了一个空行。 如何摆脱空行?

/^@/ {
    hdr = hdr $0 ORS
    next
}
split($NF, a, ":")
!seen[a[3]]++{
    out = a[3] ".txt"
    print hdr > out
}
{out = a[3] ".txt"
 print >> out 
 close(f)}

输入文件

@Loc: Cali
@Yr: 2017
@ST: blood
@header information
S1  yes yes no  yes 3y  Mother Z:AgeGroup:A1
S17 yes no  no  yes 27y Mother Z:AgeGroup:A2
B13 no  no  no  yes 1y  Mother Z:AgeGroup:A3
B5  yes yes yes yes 76y Mother Z:AgeGroup:A1
D1  yes yes no  no  18y Mother Z:AgeGroup:A1

预期 output

A1.txt

@Loc: Cali
@Yr: 2017
@ST: blood
@header information
S1  yes yes no  yes 3y  Mother Z:AgeGroup:A1
B5  yes yes yes yes 76y Mother Z:AgeGroup:A1
D1  yes yes no  no  18y Mother Z:AgeGroup:A1

A2.txt

@Loc: Cali
@Yr: 2017
@ST: blood
@header information
S17 yes no  no  yes 27y Mother Z:AgeGroup:A2

A3.txt

@Loc: Cali
@Yr: 2017
@ST: blood
@header information
B13 no  no  no  yes 1y  Mother Z:AgeGroup:A3

但是我的脚本得到的是

A1.txt

@Loc: Cali
@Yr: 2017
@ST: blood
@header information

S1  yes yes no  yes 3y  Mother Z:AgeGroup:A1
B5  yes yes yes yes 76y Mother Z:AgeGroup:A1
D1  yes yes no  no  18y Mother Z:AgeGroup:A1

A2.txt

@Loc: Cali
@Yr: 2017
@ST: blood
@header information

S17 yes no  no  yes 27y Mother Z:AgeGroup:A2

A3.txt

@Loc: Cali
@Yr: 2017
@ST: blood
@header information

B13 no  no  no  yes 1y  Mother Z:AgeGroup:A3

由于您每次都在hdr字段中附加ORS ,然后在使用print hdr > out它最终会 append 另一个换行符。

您应该像这样使用printf

printf "%s", hdr > out
$ cat tst.awk
BEGIN { FS=":" }
/^@/ {
    hdr = hdr $0 ORS
    next
}
!($NF in out) {
    out[$NF] = $NF ".txt"
    printf "%s", hdr > out[$NF]
}
{
    print >> out[$NF]
    close(out[$NF])
}

$ awk -f tst.awk file

$ head *.txt
==> A1.txt <==
@Loc: Cali
@Yr: 2017
@ST: blood
@header information
S1  yes yes no  yes 3y  Mother Z:AgeGroup:A1
B5  yes yes yes yes 76y Mother Z:AgeGroup:A1
D1  yes yes no  no  18y Mother Z:AgeGroup:A1

==> A2.txt <==
@Loc: Cali
@Yr: 2017
@ST: blood
@header information
S17 yes no  no  yes 27y Mother Z:AgeGroup:A2

==> A3.txt <==
@Loc: Cali
@Yr: 2017
@ST: blood
@header information
B13 no  no  no  yes 1y  Mother Z:AgeGroup:A3

代码中最大的问题是split($NF, a, ":")行,它会触发 awk 打印当前行,因此当您运行它时,您一定已经看到所有输入都回显到屏幕上。 这在你的问题中值得一提。 如果你真的想以这种方式使用split()那么你应该把它放在一个动作块中,而不是作为一个条件,即{ split($NF, a, ":") }

除此之外:

  1. 您的代码中有close(f)但没有名为f的变量,因此它什么都不做,让您面临“打开的文件过多”错误或执行速度降低的风险,并且
  2. 在填充 hdr 时,您将 ORS 附加到每条 header 行的末尾,但随后还通过使用print而不是printf再次添加它到 output 之后,打印了每个额外的 hdr 块 hdr。

对于您展示的样品,请尝试遵循awk代码。 使用您显示的示例编写和测试,应该在任何awk版本中工作(尽管我在 GNU awk中测试过)。

awk '
BEGIN  { FS=OFS=":" }
FNR==NR{
  header=(header?header ORS:"") $0
  next
}
prev!=$NF{
  close(outputFile)
  outputFile=$3".txt"
  print header ORS > (outputFile)
}
{
  print > (outputFile)
  prev=$NF
}
' <(awk '/^@/{print;next} {exit}' Input_file) <(grep -v '^@' Input_file | sort -t: -k1.1)

代码说明:在此处添加上述代码的详细说明。

  • 首先,我正在运行代码awk '/^@/{print;next} {exit}' Input_file (检查最后一行的第一个参数到主awk )。 我只打印从@开始并尽快退出的行,任何非@行都按照显示的示例出现。 此 output 作为第一组输入发送到主awk
  • 然后我运行代码grep -v '^@' Input_file | sort -t: -k1.1 grep -v '^@' Input_file | sort -t: -k1.1 ,通过这个,我只是将不是从@开始的每一行作为主awk的第二输入。
  • 现在在主要的awk代码中:我正在使用条件FNR==NR当第一个输入(上面在我的第一个点中提到的)被读取时,这将是 TRUE。 在这段代码中,我正在创建名为headerawk变量,它的所有行都用新行分隔,以供以后使用。
  • 这里的next非常重要,因为它将跳过从这里开始的所有进一步的语句,直到FNR==NR为 TRUE。
  • 一旦完成读取第一个输入并读取第二个输入,然后只需检查prev是否不等于当前行的第三个字段,然后只需在后端closing output 文件(我们需要在其中获取输出)基本上避免too many files opened错误. 将当前第三个字段的值设置为 output 文件名。
  • 在其他情况下,如果第三个字段/列值相同,则只需将当前行打印到outputFile变量(其中包含 output 文件名)并将当前 $3 的值分配给 outputFile 以在下一行检查。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM