web-dev-qa-db-ja.com

ファイルをパターンで2つの部分に分割する

大きなファイルをパターンで2つの部分に分割する方法は?

file.txtの例を示します:

ABC
EFG
XYZ
HIJ
KNL

このファイルをXYZで分割して、file1XYZまでの行とfile2の残りの行を含むようにします。

14
d.putto

awkを使用すると、次のことができます。

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


説明:最初のawk引数(out=file1)は、後続の引数(largefile)の処理中に出力に使用されるファイル名を持つ変数を定義します。 awkプログラムは、変数out{print >out})。パターンXYZが見つかると、出力変数は新しいファイル({out="file2}")は、後続のデータ行を印刷するためのターゲットとして使用されます。

参考文献:

10
Janis

これは csplit の仕事です:

csplit -sf file -n 1 large_file /XYZ/

silentlyファイルを分割し、pre fix fileおよびnumberedで1桁を使用してピースを作成します。 file0など。/regex/を使用すると分割されますが、regexに一致する行は含まれません。 およびに分割するには、regexに一致する行を含め、+1オフセットを追加します。

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

これにより、file0file1の2つのファイルが作成されます。 file1およびfile2という名前を付ける必要がある場合は、常に空のパターンをcsplitコマンドに追加して、最初のファイルを削除します。

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

file0file1file2を作成しますが、file0は空なので、安全に削除できます。

rm -f file0
14
don_crissti
{ sed '/XYZ/q' >file1; cat >file2; } <infile

GNU sedでは、-unbufferedスイッチ。他のほとんどのsedsは問題なく動作します。

XYZを除外するには...

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

最新のkshを使用すると、上記のsedベースの回答の1つのシェルバリアント(つまり、sedなし)が表示されます。

{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1


そしてkshだけの別のバリアント(つまり、catも省略):

{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1


(純粋なkshソリューションは非常にパフォーマンスが高いようです。2.4GBのテストファイルでは、19〜21秒必要でしたが、sed/catベースのアプローチ)。

6
Janis

GNU sed:

sed -n -e '1,/XYZ/w file1' -e '/XYZ/,${/XYZ/d;w file2' -e '}' large_file
3
Cyrus

簡単なハックは、ターゲットパターンが一致したかどうかに応じて、STDOUTまたはSTDERRに印刷することです。次に、シェルの リダイレクト演算子 を使用して、それに応じて出力をリダイレクトできます。たとえば、Perlでは、入力ファイルがfと呼ばれ、2つの出力ファイルがf1およびf2

  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
    
1
terdon