我有一个名为的文本文件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
Run Code Online (Sandbox Code Playgroud)
我想把它分成三个文本文件:entry1.txt, entry2.txt, entry3.txt. 它们的内容如下。
entry1.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
Run Code Online (Sandbox Code Playgroud)
entry2.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
Run Code Online (Sandbox Code Playgroud)
entry3.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
Run Code Online (Sandbox Code Playgroud)
换句话说,该[字符表示应该开始一个新文件。条目([ entry*],其中*是整数)始终按数字顺序排列,并且是从 1 到 N 开始的连续整数(在我的实际输入文件中,N = 200001)。
有什么办法可以在 bash 中完成自动文本文件拆分?我的实际输入entry.txt实际上包含 200,001 个条目。
Gil*_*il' 17
使用来自 GNU coreutils 的csplit(非嵌入式 Linux,Cygwin):
csplit -f entry -b '%d.txt' entry.txt '/^\[ .* \]$/' '{*}'
Run Code Online (Sandbox Code Playgroud)
您最终会得到一个额外的空文件entry0.txt(包含第一个标题之前的部分)。
标准csplit缺少{*}无限重复器和-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
Run Code Online (Sandbox Code Playgroud)
ter*_*don 11
这是一个不错的,简单的,呆呆的单行:
$ gawk '/^\[/{match($0, /^\[ (.+?) \]/, k)} {print >k[1]".txt" }' entry.txt
Run Code Online (Sandbox Code Playgroud)
这将适用于任何文件大小,无论每个条目中的行数如何,只要每个条目标题看起来像[ 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的较大的文件。
rus*_*ush 10
在 perl 中,它可以更简单地完成:
perl -ne 'open(F, ">", ($1).".txt") if /\[ (entry\d+) \]/; print F;' file
Run Code Online (Sandbox Code Playgroud)
这是一个简短的 awk 单行代码:
awk '/^\[/ {ofn=$2 ".txt"} ofn {print > ofn}' input.txt
Run Code Online (Sandbox Code Playgroud)
这是如何运作的?
/^\[/ 匹配以左方括号开头的行,并且{ofn=$2 ".txt"}将变量设置为第二个空格分隔的单词作为我们的输出文件名。然后,ofn 是一个条件,如果设置了变量,则评估为真(从而导致第一个标题之前的行被忽略){print > ofn} 将当前行重定向到指定的文件。请注意,如果紧凑性让您满意,则可以删除此 awk 脚本中的所有空格。
还要注意,上面的脚本确实需要节标题周围有空格,而不是在它们里面。如果您希望能够处理像[foo]和这样的节标题[ this that ],则需要更多的代码:
awk '/^\[/ {sub(/^\[ */,""); sub(/ *\] *$/,""); ofn=$0 ".txt"} ofn {print > ofn}' input.txt
Run Code Online (Sandbox Code Playgroud)
这使用 awk 的sub()函数来去除前导和尾随方括号加空格。请注意,根据标准 awk 行为,这会将空格(字段分隔符)折叠为单个空格(即[ this that ]保存到"this that.txt")。如果保持输出文件名中的原始空格很重要,您可以通过设置 FS 进行试验。