我想将一个大文件(> 15G,几百万条记录)分块为更小的块,并按定义的记录数进行。我正在使用Ubuntu 16.04。
以下是规则:
我搜索了类似的问题like this one,但找不到确切的答案。
这是输入文件语法的示例。
example.sdf
Item1
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.7946 2.9241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.9708 2.9673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
3
$$$$
Element2
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.6161 1.7634 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.7956 1.8496 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
5
$$$$
Something3
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.0580 0.5134 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
-3.5772 1.1545 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
10
$$$$
n = 2所需的输出:
example.sdf.chunk000001
Item1
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.7946 2.9241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.9708 2.9673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
3
$$$$
Element2
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.6161 1.7634 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-2.7956 1.8496 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
5
$$$$
example.sdf.chunk000002
Something3
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.0580 0.5134 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
-3.5772 1.1545 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
10
$$$$
此刻,我尝试通过split和awk实现此功能(请参见下文),但这看起来很笨拙。我也尝试看过csplit,但是找不到任何在每个块中设置定义数量的记录的选项。
split命令工作得很好,但是不接受'$$$$'分隔符,因为它是多个字符。我可以通过用单个字符(@)替换此模式来使其工作,但是如果在SDF文件中找到另一个字符,则可能会出错。
# replace the separator with a dummy
sed -e 's/\$\$\$\$/@/g' export.sdf > example.sdf.tmp
# split the file (3 records) into smaller chunks (xaa, xab, ect.) with max 2 records
split -t @ -l 2 example.sdf.tmp
# replace the dummy with the proper separator
for f in xa*; do tail -n +2 $f |sed 's/@/\$\$\$\$/g' > $f.fixed; done
不幸的是,在编辑输入文件以及随后的每个块时,它看起来并不是很优化,因此我尝试使用awk。
我是awk的新手,但我设法做到了:
awk 'NR%2==1 {x=sprintf(".chunk%06d",++i);} END {printf "%s",$0} {print>FILENAME x}' RS="\\$\\$\\$\\$" ORS="\$\$\$\$" example.sdf
第一个块看上去完全是我要寻找的东西,但是第二个有两个错误:
example.sdf.chunk000002
[ blank line ]
Something3
Mrv171c009131823372D
2 1 0 0 0 0 999 V2000
-3.0580 0.5134 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
-3.5772 1.1545 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
M END
> <property_1>
10
$$$$
$$$$
如您所见,在文件的开头有一个空行(我无法显示,因此我键入了[空白行]),在最后一块的末尾有一个最终的结束模式。我还尝试了一个具有9条记录的文件,在第2-5块的开头得到了空行,在第5块的末尾得到了最后一个额外的'$$$$'。
如何解决此问题,以便获得预期的输出?
任何帮助将不胜感激!
乔斯·曼努埃尔
答案 0 :(得分:0)
使用GNU awk:
awk -v RS='\\$\\$\\$\\$\n' -v nb=2 -v c=1 '
{
file=sprintf("%s%s%06d",FILENAME,".chunk",c)
printf "%s%s",$0,RT > file
}
NR%nb==0 {c++}
' example.sdk
模式RS
的记录分隔符$$$$
允许立即获取全部块。
变量nb
保存每个文件的块数,c
是文件名的计数数。