我将大文本文件拆分成多个较小的文件有点麻烦。我的文本文件的语法如下:
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
(dasdas#42319 blaablaa 50 50,内容内容,更多内容和内容结论都是他们自己单独的行,后面跟一个空白行是该信息表的结尾。我文件中的典型信息表有10个之间的任何地方-40行。)
我希望将此文件拆分为n个较小的文件,其中n是内容表的数量 那是
dasdas #42319 blaablaa 50 50
content content
more content
content conclusion
将是它自己的单独文件,(whateverN.txt)
和
asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion
再一个单独的文件,无论N + 1.txt等等。
似乎awk
或Perl
是非常好的工具,但在语法之前从未使用它们有点莫名其妙。
我发现这两个问题几乎与我的问题相对应,但未能修改语法以满足我的需求。
Split text file into multiple files&
https://unix.stackexchange.com/questions/46325/how-can-i-split-a-text-file-into-multiple-text-files
如何修改命令行输入,以便解决我的问题?
答案 0 :(得分:24)
将RS
设置为null会告诉awk使用一个或多个空行作为记录分隔符。然后,您只需使用NR
设置与每条新记录对应的文件名称:
awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt
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
$
答案 1 :(得分:3)
Perl有一个称为输入记录分隔符的有用功能。 $/
。
这是'标记'用于在读取文件时分离记录。
所以:
#!/usr/bin/env perl
use strict;
use warnings;
local $/ = "\n\n";
my $count = 0;
while ( my $chunk = <> ) {
open ( my $output, '>', "filename_".$count++ ) or die $!;
print {$output} $chunk;
close ( $output );
}
就像那样。 <>
是魔法&#39; filehandle,因为它读取管道数据或从命令行指定的文件(打开它们并读取它们)。这与sed
或grep
的工作方式类似。
这可以减少到一个班轮:
perl -00 -pe 'open ( $out, '>', "filename_".++$n ); select $out;' yourfilename_here
答案 2 :(得分:2)
您可以使用此awk
,
awk 'BEGIN{file="content"++i".txt"} !NF{file="content"++i".txt";next} {print > file}' yourfile
(OR)
awk 'BEGIN{i++} !NF{++i;next} {print > "filename"i".txt"}' yourfile
更易读的格式:
BEGIN {
file="content"++i".txt"
}
!NF {
file="content"++i".txt";
next
}
{
print > file
}
答案 3 :(得分:1)
您可以使用csplit
命令:
csplit \
--quiet \
--prefix=whatever \
--suffix-format=%02d.txt \
--suppress-matched \
infile.txt /^$/ {*}
POSIX csplit
仅使用简短选项,不知道--suffix
和--suppress-matched
,因此这需要GNU csplit
。
这是选项的作用:
--quiet
–禁止输出文件大小--prefix=whatever
–使用whatever
代替默认的xx
文件名前缀--suffix-format=%02d.txt
–将.txt
附加到默认的两位数字后缀--suppress-matched
–不包括与分割输入的模式匹配的行/^$/ {*}
–尽可能频繁地在模式“空行”(/^$/
)({*}
)上拆分答案 4 :(得分: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++;
}
perl
文档可以解释您不理解的任何单个命令,但此时您也应该查看教程。
答案 5 :(得分:0)
awk -v RS="\n\n" '{for (i=1;i<=NR;i++); print > i-1}' file.txt
将记录分隔符设置为空行,将每个记录打印为编号为1,2,3等的单独文件。最后一个文件(仅)以空行结束。
答案 6 :(得分:0)
尝试这个bash脚本
#!/bin/bash
i=1
fileName="OutputFile_$i"
while read line ; do
if [ "$line" == "" ] ; then
((++i))
fileName="OutputFile_$i"
else
echo $line >> "$fileName"
fi
done < InputFile.txt
答案 7 :(得分:0)
如果出现“打开文件过多”错误,如下所示...
awk: whatever-18.txt makes too many open files
input record number 18, file file.txt
source line number 1
您可能需要在创建新文件之前关闭新创建的文件,如下所示。
awk -v RS= '{close("whatever-" i ".txt"); i++}{print > ("whatever-" i ".txt")}' file.txt
答案 8 :(得分:0)
您也可以尝试split -p "^$"