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