【发布时间】:2018-09-14 22:57:24
【问题描述】:
我想将一个大文件(>15G,几百万条记录)分块为具有定义数量的记录的较小块。我正在使用 Ubuntu 16.04。
规则如下:
- 对于可移植性问题,我想坚持使用 UNIX 命令。
- 有一个特定的模式定义输入文件中每条记录的结尾 ('$$$$')。
- 应保留此模式以将记录分隔成块
- 每个块应该包含 n 条记录
- 每条记录的行数都可以不同。
我搜索了类似的问题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 很陌生,但我设法得到了这个:
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
$$$$
$$$$
如您所见,文件开头有一个空行(我无法显示,所以我输入了 [blank line]),最后一个块的末尾有一个最终结束模式。我还尝试了一个包含 9 条记录的文件,我在块 2-5 的开头得到了空行,在块 5 的末尾得到了最后一个额外的 '$$$$'。
如何解决此问题,以便获得预期的输出?
任何帮助将不胜感激!
何塞·曼努埃尔
【问题讨论】: