按模式将文件分为两部分


14

如何以模式将大文件分为两部分?

举个例子file.txt

ABC
EFG
XYZ
HIJ
KNL

我想这个文件在拆分XYZ,使得file1包含排队到XYZ休息的线条file2


XYZ行是否应包含在输出中?
terdon

@terdon在我的情况下,“ XYZ”行不应成为file2的一部分。但是,如果您有办法做到这一点,请添加答案。在某些其他情况下可能会很有用。
d.putto,2015年

公平,完成。
terdon

Answers:


10

有了awk您就可以做到:

awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile


说明:第一个awk参数(out=file1)定义了一个变量,其文件名将在largefile处理后续参数()时用于输出。该awk程序将打印所有行于由变量指定的文件out{print >out})。如果XYZ将找到模式,则将重新定义输出变量以指向新文件({out="file2}"),该文件将用作打印后续数据行的目标。

参考文献:


14

这是一项工作csplit

csplit -sf file -n 1 large_file /XYZ/

silently分割文件,创建与前片ffilen使用一个单一的数字umbered,如file0等。注意,使用/regex/起来会拆分,但不包括行匹配regex。要分割包括行匹配,请regex添加一个+1偏移量:

csplit -sf file -n 1 large_file /XYZ/+1

这将创建两个文件 file0file1。如果您绝对需要为它们命名file1,则file2可以始终在csplit命令中添加一个空模式并删除第一个文件:

csplit -sf file -n 1 large_file // /XYZ/+1

创建file0file1以及file2但是file0是空的,所以你可以放心地将其删除:

rm -f file0

我认为,这是最简单的答案。您所要做的就是列出一些模式,文件将按顺序拆分。辉煌!
亨利·布莱斯

6

对于现代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秒)。


这是非常快的。但我不认为你需要readprint-你应该让它去输出自己的所有。如果您完全构建AST工具包并ksh编译所有内置文件,则性能会更好-实际上,这sed不是其中之一对我来说很奇怪。但是用类似while <file do我想的东西,你不需要sed那么多……
mikeserv

我很好奇- awk您的基准测试表现如何?虽然我敢肯定,ksh将有可能永远赢得这场战斗,如果你使用的是GNU sed你不是很公平sed- GNU的-unbuffered是小便穷人的办法,以确保POSIXLY描述符的偏移留在程序中退出,其中,它-应该没有必要减慢程序的正常运行-缓冲很好-所有sed要做的就是完成后查找描述符。无论出于什么原因,GNU都会扭转这种想法。
mikeserv

@mikeserv; 重定向模式匹配将一直进行到找到模式为止,并且如果未如所示进行显式操作,则不会打印带有找到的模式的行。(至少这显示了我的测试。)请注意,没有while;作为<##重定向操作符的定义副作用,隐式完成了打印。并且只有匹配的行需要打印。(这样,shell功能实现对于包括incl./excl。的支持最为灵活。)while我希望显式循环会明显慢一些(但尚未检查)。
Janis

1
@mikeserv; 啊好吧。顺便说一句,我只是尝试了head而不是read; 看起来似乎有点慢,但这是更简短的代码:{ head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3
Janis

1
@mikeserv; 好点子; 不是。但是,当我激活内置函数(完成并检查结果)时,很奇怪,它是相同的数字。(也许与读取相比,有些函数调用开销
更大

6
{ sed '/XYZ/q' >file1; cat >file2; } <infile

对于GNU,sed您应该使用-unbuffered开关。大多数其他sed的应该可以工作。

忽略XYZ ...

{ sed -n '/XYZ/q;p'; cat >file2; } <infile >file1

3

尝试使用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
don_crissti

1

一个简单的技巧是根据目标图案是否匹配,将其打印到STDOUT或STDERR。然后,您可以使用外壳程序的重定向运算符相应地重定向输出。例如,在Perl中,假设调用了输入文件,并且假定f了两个输出文件f1f2

  1. 丢弃与拆分模式匹配的行:

    perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
  2. 包括匹配的行:

    perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2

或者,打印到不同的文件句柄:

  1. 丢弃与拆分模式匹配的行:

    perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
    if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
    
  2. 包括匹配的行:

    perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
              $a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
    
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.