如何以模式将大文件分为两部分?
举个例子file.txt
:
ABC
EFG
XYZ
HIJ
KNL
我想这个文件在拆分XYZ
,使得file1
包含排队到XYZ
休息的线条file2
。
如何以模式将大文件分为两部分?
举个例子file.txt
:
ABC
EFG
XYZ
HIJ
KNL
我想这个文件在拆分XYZ
,使得file1
包含排队到XYZ
休息的线条file2
。
Answers:
有了awk
您就可以做到:
awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile
说明:第一个awk
参数(out=file1
)定义了一个变量,其文件名将在largefile
处理后续参数()时用于输出。该awk
程序将打印所有行于由变量指定的文件out
({print >out}
)。如果XYZ
将找到模式,则将重新定义输出变量以指向新文件({out="file2}"
),该文件将用作打印后续数据行的目标。
参考文献:
这是一项工作csplit
:
csplit -sf file -n 1 large_file /XYZ/
将s
ilently分割文件,创建与前片f
九file
和n
使用一个单一的数字umbered,如file0
等。注意,使用/regex/
起来会拆分,但不包括行匹配regex
。要分割并包括行匹配,请regex
添加一个+1
偏移量:
csplit -sf file -n 1 large_file /XYZ/+1
这将创建两个文件 file0
和file1
。如果您绝对需要为它们命名file1
,则file2
可以始终在csplit
命令中添加一个空模式并删除第一个文件:
csplit -sf file -n 1 large_file // /XYZ/+1
创建file0
,file1
以及file2
但是file0
是空的,所以你可以放心地将其删除:
rm -f file0
对于现代ksh
版本sed
,这是上述sed
基础答案之一的shell变体(即,不带):
{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1
还有一个ksh
单独的变体(即也省略了cat
):
{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1
(纯ksh
解决方案似乎性能很好;在2.4 GB的测试文件上,它需要19-21秒,而使用sed
/ cat
方法则需要39-47秒)。
awk
您的基准测试表现如何?虽然我敢肯定,ksh
将有可能永远赢得这场战斗,如果你使用的是GNU sed
你不是很公平sed
- GNU的-u
nbuffered是小便穷人的办法,以确保POSIXLY描述符的偏移留在程序中退出,其中,它-应该没有必要减慢程序的正常运行-缓冲很好-所有sed
要做的就是完成后查找描述符。无论出于什么原因,GNU都会扭转这种想法。
while
;作为<##
重定向操作符的定义副作用,隐式完成了打印。并且只有匹配的行需要打印。(这样,shell功能实现对于包括incl./excl。的支持最为灵活。)while
我希望显式循环会明显慢一些(但尚未检查)。
head
而不是read
; 看起来似乎有点慢,但这是更简短的代码:{ head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3
。
尝试使用GNU sed:
sed -n -e '1,/XYZ/w file1' -e '/XYZ/,${/XYZ/d;w file2' -e '}' large_file
sed -e '1,/XYZ/{w file1' -e 'd}' large_file > file2
一个简单的技巧是根据目标图案是否匹配,将其打印到STDOUT或STDERR。然后,您可以使用外壳程序的重定向运算符相应地重定向输出。例如,在Perl中,假设调用了输入文件,并且假定f
了两个输出文件f1
和f2
:
丢弃与拆分模式匹配的行:
perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
包括匹配的行:
perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
或者,打印到不同的文件句柄:
丢弃与拆分模式匹配的行:
perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
包括匹配的行:
perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
$a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
XYZ
行是否应包含在输出中?