在每个空行上拆分大文本文件

tro*_*l e 15 bash perl awk

我有点麻烦将大文本文件拆分成多个较小的文本文件.我的文本文件的语法如下:

dasdas #42319 blaablaa 50 50
content content
more content
content conclusion

asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion

asdasd #299 yadayada 60 40
content
content
contend done
...and so on
Run Code Online (Sandbox Code Playgroud)

(dasdas#42319 blaablaa 50 50,内容内容,更多内容和内容结论都是他们自己的单独行,后面跟着一个空白行是该信息表的结尾.我文件中的典型信息表有10-40行之间的任何地方. )

我希望将此文件拆分为n个较小的文件,其中n是内容表的数量.
那是

dasdas #42319 blaablaa 50 50
content content
more content
content conclusion
Run Code Online (Sandbox Code Playgroud)

将是它自己的单独文件,(whateverN.txt)

asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion
Run Code Online (Sandbox Code Playgroud)

再一个单独的文件,无论N + 1.txt等等.

它似乎awk或是Perl非常好的工具,但在语法之前从未使用它们有点莫名其妙.

我发现这两个问题几乎与我的问题相对应,但未能修改语法以满足我的需求.

将文本文件拆分为多个文件&
https://unix.stackexchange.com/questions/46325/how-can-i-split-a-text-file-into-multiple-text-files

应如何修改命令行输入,以便解决我的问题?

jas*_*jas 25

设置RS为null会告诉awk使用一个或多个空行作为记录分隔符.然后,您只需使用NR设置与每个新记录对应的文件的名称:

 awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt
Run Code Online (Sandbox Code Playgroud)

RS:这是awk的输入记录分隔符.它的默认值是一个包含单个换行符的字符串,这意味着输入记录由一行文本组成.它也可以是空字符串,在这种情况下,记录由空行或正则表达式分隔,在这种情况下,记录由输入文本中的正则表达式的匹配分隔.

$ cat file.txt
dasdas #42319 blaablaa 50 50
content content
more content
content conclusion

asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion

asdasd #299 yadayada 60 40
content
content
contend done

$ awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt

$ ls whatever-*.txt
whatever-1.txt  whatever-2.txt  whatever-3.txt

$ cat whatever-1.txt 
dasdas #42319 blaablaa 50 50
content content
more content
content conclusion

$ cat whatever-2.txt 
asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion

$ cat whatever-3.txt 
asdasd #299 yadayada 60 40
content
content
contend done
$ 
Run Code Online (Sandbox Code Playgroud)

  • 我们如何将它保存在变量数组中? (2认同)
  • 简单的解决方案,不错!如果要将输出文件名模式作为变量传递,则可以选择以下内容:`awk -v RS = -v PATTERN =“ whatever-%d.txt”'{FILE = sprintf(PATTERN,NR); 打印> FILE}'$ filename` (2认同)
  • 请注意,您可能以这种方式打开了太多文件句柄。只有 gnu awk 会自动解决这个问题。更好的版本是: `awk -v RS= '{f="whatever=" NR ".txt"; 打印> f;关闭(f)}'文件` (2认同)

Ben*_* W. 10

您可以使用以下csplit命令:

\n\n
csplit \\\n    --quiet \\\n    --prefix=whatever \\\n    --suffix-format=%02d.txt \\\n    --suppress-matched \\\n    infile.txt /^$/ {*}\n
Run Code Online (Sandbox Code Playgroud)\n\n

POSIXcsplit仅使用短选项并且不知道--suffix--suppress-matched,因此这需要 GNU csplit

\n\n

这就是选项的作用:

\n\n
    \n
  • --quiet\xe2\x80\x93 抑制文件大小的输出
  • \n
  • --prefix=whatever\xe2\x80\x93 使用whatever默认xx文件名前缀
  • \n
  • --suffix-format=%02d.txt\xe2\x80\x93 附加.txt到默认的两位数字后缀
  • \n
  • --suppress-matched\xe2\x80\x93 不包含与分割输入的模式匹配的行
  • \n
  • /^$/ {*}/^$/\xe2\x80\x93尽可能频繁地在模式“空行”( ) 上分割( {*})
  • \n
\n


Nic*_*k P 0

因为今天是星期五,我感觉有点帮助......:)

尝试这个。如果文件像您暗示的那么小,最简单的方法就是一次读取所有文件并在内存中工作。

use strict;
use warnings;

# slurp file
local $/ = undef;
open my $fh, '<', 'test.txt' or die $!;
my $text = <$fh>;
close $fh;

# split on double new line
my @chunks = split(/\n\n/, $text);

# make new files from chunks
my $count = 1;
for my $chunk (@chunks) {
    open my $ofh, '>', "whatever$count.txt" or die $!;
    print $ofh $chunk, "\n";
    close $ofh;
    $count++;
}
Run Code Online (Sandbox Code Playgroud)

这些perl文档可以解释您不理解的任何单个命令,但此时您可能还应该查看教程。