2015-10-23 12 views
10

Ich habe ein bisschen Mühe, eine große Textdatei in mehrere kleinere zu teilen. Syntax meiner Textdatei ist die folgende:Große Textdatei auf jeder leeren Zeile teilen

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, Content-Inhalt, mehr Inhalt & Inhalt Schluss sind alle ihre eigenen separaten Linien durch eine Leerzeile ist das Ende dieser Informationstabelle Eine typische Informationstabelle in meiner Datei hat irgendwo zwischen 10-40 Zeilen.)

Ich würde diese Datei in n kleinere Dateien aufteilen, wobei n die Menge der Inhaltstabellen ist.
Das

ist wäre es separat einer eigenen Datei, (whateverN.txt)

und

asdasd #92012 blaablaa 30 70 
content again 
more of it 
content conclusion 

wieder eine separate Datei whateverN + 1.txt und so weiter.

Es scheint wie awk oder Perl sind nette Tools für diese, aber nie zuvor verwendet, bevor die Syntax ist irgendwie verwirrend.

Ich habe diese beiden Fragen gefunden, die meinem Problem fast entsprechen, aber es ist mir nicht gelungen, die Syntax an meine Bedürfnisse anzupassen.

Split text file into multiple files &
https://unix.stackexchange.com/questions/46325/how-can-i-split-a-text-file-into-multiple-text-files

Wie soll man die Befehlszeileneingaben ändern, so dass es mein Problem löst?

+2

Ich wette, müssen lernen, wie sie zu benutzen (awk, Perl, oder was auch immer) ein wenig, bevor Sie versuchen, sie zu benutzen, um Ihre Probleme zu lösen . –

+0

Oder gibt es eine Sprache, die Sie wissen, dass Sie eine Lösung versuchen können? – mwp

+0

Sehen Sie sich bitte [editing-help] (http://stackoverflow.com/editing-help) an. – Cyrus

Antwort

0

Da es Freitag und ich bin ein bisschen hilfreich Gefühl ... :)

Versuchen Sie dies. Wenn die Datei so klein ist, wie Sie meinen, ist es am einfachsten, sie alle gleichzeitig zu lesen und im Speicher zu arbeiten.

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++; 
} 

Die perl docs können alle einzelnen Befehle erklären Sie nicht verstehen, aber an diesem Punkt sollten Sie wahrscheinlich auch ein Tutorial suchen.

+0

Die Einstellung '$ /' ist wahrscheinlich ein besserer Ansatz. – Sobrique

+0

Richtig, und das 'local' ist auch nicht notwendig. Kraft der Gewohnheit. –

+0

Das ist aber eine gute Angewohnheit und eine, die sonst nichts schadet;) – Sobrique

1

können Sie verwenden diese 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 

Mehr lesbares Format:

BEGIN { 
     file="content"++i".txt" 
} 
!NF { 
     file="content"++i".txt"; 
     next 
} 
{ 
     print > file 
} 
+0

Anstelle von $ 0 ~/^ $/'könnte man einfach'/^ $/'oder häufiger'! NF' verwenden. Sie wollen 'print> file', nicht' print >> file' - shell und awk haben eine andere Semantik für '>' vs '' '. –

+1

@EdMorton, Sie haben Recht. Aktualisiert. Danke für den Hinweis ('shell' und' awk' haben unterschiedliche Semantiken für '>' vs '' ''). – sat

+0

Verwenden Sie 'print> (" Dateiname "i" .txt ")' anstelle von 'print>" Dateiname "i" .txt "', da die Bedeutung dieser Anweisung in POSIX nicht definiert ist und einige Benutzer sie als '(print > "Dateiname") i ".txt" 'oder etwas anderes unerwünscht. –

0
awk -v RS="\n\n" '{for (i=1;i<=NR;i++); print > i-1}' file.txt 

Sätze voneinander zu trennen sind als Leerzeile, druckt jede notieren Sie als separate Datei nu mbered 1, 2, 3 usw. Die letzte Datei (nur) endet in der Leerzeile.

+0

Die Verwendung mehrerer Zeichen für RS macht dieses Gawk spezifisch, aber Sie sollten trotzdem 'RS =" "' verwenden. Gib auch immer die rechte Seite der Ausgabeumleitung in Klammern an, da einige Benutzer "print i-1" als "(print i) -i" interpretieren. Vor allem aber - die Logik ist falsch und es werden NR-Vorkommen jedes Datensatzes gedruckt. –

0

diesen Bash-Skript auch als Datensatz-Trenn

#!/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 
+0

Das wird den Inhalt seiner Eingabedatei verfälschen und unterschiedliche Ausgaben basierend auf dem Inhalt der Eingabedatei und dem Inhalt des Verzeichnisses, aus dem Sie es ausführen, erzeugen. Schreiben Sie KEINE Shell-Schleifen, nur um Text zu manipulieren. Siehe http: //unix.stackexchange.com/q/169716/133219 –

15

Einstellung RS auf null awk eine sagt zu verwenden oder mehr Leerzeilen versuchen. Dann können Sie einfach NR verwenden Sie den Namen der Datei, in jedem neuen Datensatz entsprechend eingestellt:

awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt 

RS: Dies ist awk des Eingangs voneinander zu trennen sind. Der Standardwert ist eine Zeichenfolge, die ein einzelnes Newline-Zeichen enthält. Dies bedeutet, dass ein Eingabedatensatz aus einer einzelnen Textzeile besteht. Es kann auch die Nullzeichenfolge sein. In diesem Fall werden Datensätze durch Läufe von Leerzeilen oder einem regulären Ausdruck getrennt. In diesem Fall werden Datensätze durch Übereinstimmungen von regexp im Eingabetext getrennt.

$ 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

Yup, das ist, wie Sie es tun, +1. –

+0

Wie speichern wir es in einem variablen Array? – Chand

3

Perl hat eine nützliche Funktion, um den Eingabedatensatz-Separator bezeichnet. $/.

Dies ist der 'Marker' zum Trennen von Datensätzen beim Lesen einer Datei.

So:

#!/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); 
} 

Einfach so. Das <> ist das "magische" Dateihandle, da es piped Daten oder von Dateien liest, die auf der Kommandozeile angegeben sind (öffnet sie und liest sie). Dies ist ähnlich wie sed oder grep funktionieren.

Dies kann zu einem Einzeiler reduziert werden: Sie

perl -00 -pe 'open ($out, '>', "filename_".++$n); select $out;' yourfilename_here 
+0

-00? Nun, das ist etwas Neues. Aber ich versuche, einen Liner zu vermeiden :) –

+0

Das mache ich generell, aber wenn wir in einem 'Awk'-Rennen sind, versuche ich, sie zum Vergleich mit einzubeziehen. (Aber so viel wie möglich _nach_ irgendeinem Code, der klarer darstellt). – Sobrique

+0

Danke! Das war's! Als erstes führte dieser Befehl zu dem gleichen Szenario, das ich mit anderen Skripten hatte. Der Grund war anscheinend, dass meine Eingabedateien (jede von ihnen 4-8M Zeilen lang) falsche Zeilentrenner oder etwas Wacks hatten. Jedes Mal, wenn ich sie in einem Texteditor öffne, würden sie gut aussehen. Das Ausführen dieses Befehls führte jedoch zu einer einzigen Datei, die mit der Eingabedatei identisch ist. Aber nachdem ich jeden Datensatz in eine leere Seite im Texteditor kopiert und eingefügt habe und auf Speichern geklickt habe, änderte sich die Dateigröße ein wenig (wie 1M in einer 150MB Datei) und danach lief dieser Befehl gut. –

Verwandte Themen