我有一个名为的文本文件entry.txt
,其中包含以下内容:
[ entry1 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3633 3634 3636 3690 3691 3693 3766
3767 3769 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5628 5629 5631
[ entry2 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4526
4527 4529 4583 4584 4586 4773 4774 4776 5153 5154
5156 5628 5629 5631
[ entry3 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4241
4242 4244 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5495 5496 5498 5628 5629 5631
我想将其分成三个文本文件:entry1.txt
、entry2.txt
、entry3.txt
.它们的内容如下。
条目1.txt:
[ entry1 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3633 3634 3636 3690 3691 3693 3766
3767 3769 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5628 5629 5631
条目2.txt:
[ entry2 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4526
4527 4529 4583 4584 4586 4773 4774 4776 5153 5154
5156 5628 5629 5631
条目3.txt:
[ entry3 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4241
4242 4244 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5495 5496 5498 5628 5629 5631
换句话说,该[
字符指示应开始一个新文件。条目([ entry*]
,其中*
是整数)始终按数字顺序排列,并且是从 1 到 N 的连续整数(在我的实际输入文件中,N = 200001)。
有什么方法可以在 bash 中完成自动文本文件分割吗?我的实际输入entry.txt
实际上包含 200,001 个条目。
答案1
和分割来自 GNU coreutils(非嵌入式 Linux、Cygwin):
csplit -f entry -b '%d.txt' entry.txt '/^\[ .* \]$/' '{*}'
您最终会得到一个额外的空文件entry0.txt
(包含第一个标头之前的部分)。
标准分割缺少{*}
无限重复器和-b
指定后缀格式的选项,因此在其他系统上,您必须先计算部分的数量,然后重命名输出文件。
csplit -f entry -n 9 entry.txt '/^\[ .* \]$/' "{$(egrep -c '^'\[ .* \]$' <entry.txt)}"
for x in entry?????????; do
y=$((1$x - 1000000000))
mv "entry$x" "entry$y.txt"
done
答案2
这是一句漂亮、简单、令人傻眼的俏皮话:
$ gawk '/^\[/{match($0, /^\[ (.+?) \]/, k)} {print >k[1]".txt" }' entry.txt
这将适用于任何文件大小,无论每个条目中有多少行,只要每个条目标题看起来像[ blahblah blah blah ]
.注意开盘之后[
和闭盘之前的空间]
。
解释:
awk
并gawk
逐行读取输入文件。读取每一行时,其内容都会保存在$0
变量中。在这里,我们告诉gawk
匹配方括号内的任何内容,并将其匹配项保存到数组中k
。
因此,每次匹配正则表达式时,即对于文件中的每个标头,k[1] 将具有该行的匹配区域。即,“entry1”、“entry2”或“entry3”或“entryN”。
最后,我们将每一行打印到一个名为 的文件中<whatever value k currently has>.txt
,即entry1.txt、entry2.txt ...entryN.txt。
这个方法将是很多对于较大的文件,比 perl 更快。
答案3
在 Perl 中可以更简单地完成:
perl -ne 'open(F, ">", ($1).".txt") if /\[ (entry\d+) \]/; print F;' file
答案4
可以通过 python 命令行完成:
paddy$ python3 -c 'out=0
> with open("entry.txt") as f:
> for line in f:
> if line[0] == "[":
> if out: out.close()
> out = open(line.split()[1] + ".txt", "w")
> else: out.write(line)'