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


14

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

例が与えられた場合file.txt

ABC
EFG
XYZ
HIJ
KNL

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


なければならないXYZラインが出力にか含まれて?
テルドン

@terdon私の場合、「XYZ」行はfile2の一部であってはなりません。しかし、それを行う方法がある場合は、答えに追加してください。他のいくつかの場合に役立つかもしれません。
d.putto

結構です。
テルドン

回答:


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前で作品を作成、ファイルを分割fIX filen一桁を使用してumbered、例えばfile0使用していることを注意など/regex/に分割しますが、一致していることを行を含めませんregex。分割すると、ラインのマッチングを含むregex追加+1のオフセット:

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

これは、2つのファイルを作成し、 file0そしてfile1。絶対に名前file1file2付ける必要があり、常に空のパターンをcsplitコマンドに追加して最初のファイルを削除できる場合:

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

作成しfile0file1そしてfile2しかしfile0、あなたが安全に取り外すことができるように空です:

rm -f file0

これが最も簡単な答えだと思います。あなたがしなければならないのは、いくつかのパターンをリストするだけで、ファイルはそれらによって順番に分割されます。鮮やかさ!
ヘンリーブライス

6

モダンkshsedは、sed上記の回答のいずれかのシェルバリアントがあります(つまり、なし)。

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


そして、ksh単独での別のバリアント(つまり、省略cat):

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


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


それはです非常に速いです。しかし、私はあなたがする必要はないと思うreadし、printあなたはちょうどそれがすべて独自の出力に行かせなければなりません- 。ASTツールキットを完全にビルドし、すべてのkshビルトインをコンパイルするとパフォーマンスが向上しますsed。実際には、それらの1つではないのは奇妙なことです。しかし、while <file do私はあなたがsedそんなに必要としないと思うようなもので
...-mikeserv

しかし、私は興味があります- awkあなたのベンチマークでどのようにパフォーマンスしましたか?そして、私はkshおそらくこの戦いに常に勝つと確信していsedますが、GNU を使用している場合、あなたはあまり公平ではありません-GNU sed-unbufferedは、プログラムの終了時に記述子のオフセットを残すPOSIXLYへの小便なアプローチですそれ-プログラムの通常の動作を遅くする必要はないはずです-バッファリングは問題ありsedません- 完了したら記述子をlseekするだけです。何らかの理由で、GNUはその考え方を覆します。
mikeserv

@mikeserv; リダイレクトパターンの一致は、パターンが見つかるまで行われ、示されているように明示的に行われない場合、見つかったパターンを持つ行は印刷されません。(少なくとも、それは私のテストを示しています。)ないことに注意してくださいwhile。印刷は、<##リダイレクト演算子の定義された副作用として暗黙的に行われます。そして、一致する行のみが印刷を必要とします。(このようにシェル機能の実装はincl./exclをサポートするために最も柔軟性があります。)明示的なwhileループは大幅に遅くなると予想されます(ただし、チェックしていません)。
ジャニス

1
@mikeserv; うん、いいよ。ところで、私はちょうどのhead代わりに試しましたread; 少し遅いように見えますが、より簡潔なコードです{ head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3
ジャニス

1
@mikeserv; いい視点ね; そうではなかった。しかし、ビルトインを有効にすると(結果を確認して確認しただけ)、奇妙なことに同じ数字になります。(おそらく、読み取りと比較した関数呼び出しのオーバーヘッドですか?)
ジャニス

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

GNU sedでは、-unbufferedスイッチを使用する必要があります。他sedのほとんどのsでも動作するはずです。

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
短縮

1

簡単なハックは、ターゲットパターンが一致したかどうかに応じて、STDOUTまたはSTDERRに出力することです。その後、シェルのリダイレクト演算子を使用して、それに応じて出力をリダイレクトできます。たとえば、Perlでは、入力ファイルが呼び出さfれ、2つの出力ファイルが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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.