AWK每隔n行拆分文件,但将ID分组在一起

假设我有以下文件text.txt

@something
@somethingelse
@anotherthing
1
2
2
3
3
3
4
4
4
5
5
6
7
7
8
9
9
9
10
11
11
11
14
15

我想按每第 5 个数据行将其拆分为多个文件,但如果下一行的编号相同,它仍应最终出现在同一个文件中。标头应该在每个文件中,但也可以忽略并稍后重新引入。
这意味着这样的事情:

text.txt.1
@something
@somethingelse
@anotherthing
1
2
2
3
3
3

text.txt.2
@something
@somethingelse
@anotherthing
4
4
4
5
5

text.txt.3
@something
@somethingelse
@anotherthing
6
7
7
8
9
9
9

text.txt.4
@something
@somethingelse
@anotherthing
10
11
11
11
14

text.txt.5
@something
@somethingelse
@anotherthing
15

所以我在想这样的事情:

awk 'NR%5==1 && $1!=prev{i++;prev=$1}{print > FILENAME"."i}' test.txt

这两个语句单独工作但不能一起工作..使用awk可以吗?

回答

好问题。
使用您的示例,这将起作用:

awk 'BEGIN{i=1;}/@/{header= header == ""? $0 : header "n" $0; next}c>=5 && $1!=prev{i++;c=0;}{if(!c) print header>FILENAME"."i; print > FILENAME"."i;c++;prev=$1;}' test.txt

您需要去掉标题,并设置一个计数器(c在上面),NR只是输入的当前行号,当实际行数不是 5 的倍数时,它将无法满足您的需求。

分解并改进一点点:

awk 'BEGIN{i=1;}
  /@/{header= header == ""? $0 : header ORS $0; next}
  c>=5 && $1!=prev{i++;c=0;}
  !c {print header>FILENAME"."i;}
  {print > FILENAME"."i;c++;prev=$1;}
  ' test.txt

解决评论中提到的潜在问题:

awk 'BEGIN{i=1}
  /@/{header= header == ""? $0 : header ORS $0; next}
  c>=5 && $1!=prev{i++;c=0}
  !c {close(f);f=(FILENAME"."i);print header>f}
  {print>f;c++;prev=$1}
  ' test.txt

或检查Ed 的答案,该答案更精确且兼容不同的平台/版本。

  • `print > FILENAME"."i` 是每个 POSIX 的未定义行为,它需要是 `print > (FILENAME"."i)` 否则你会在某些 awks 中遇到语法错误。如果您没有在运行时关闭输出文件,那么一旦您获得超过 15 个输出文件,您还会从某些 awks 中得到“打开的文件太多”的错误信息。

回答

在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ cat tst.awk
/^@/ {
    hdr = hdr $0 ORS
    next
}
( (++numLines) % 5 ) == 1 {
    if ( $0 == prev ) {
        --numLines
    }
    else {
        close(out)
        out = FILENAME "." (++numBlocks)
        printf "%s", hdr > out
        numLines = 1
    }
}
{
    print > out
    prev = $0
}
$ awk -f tst.awk text.txt
$ head text.txt.*
==> text.txt.1 <==
@something
@somethingelse
@anotherthing
1
2
2
3
3
3

==> text.txt.2 <==
@something
@somethingelse
@anotherthing
4
4
4
5
5

==> text.txt.3 <==
@something
@somethingelse
@anotherthing
6
7
7
8
9
9
9

==> text.txt.4 <==
@something
@somethingelse
@anotherthing
10
11
11
11
14

==> text.txt.5 <==
@something
@somethingelse
@anotherthing
15


以上是AWK每隔n行拆分文件,但将ID分组在一起的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>