Aufteilen: Wie wird in verschiedene Prozentsätze aufgeteilt?

14

Wie kann ich eine Textdatei mit dem Befehl split in 70% und 30% aufteilen?

aneuryzm
quelle
Sind Sie daran gewöhnt, den Befehl split zu verwenden? Wenn nicht, können Sie dies einfach mit direkter Textmanipulation tun, ganz sicher mit Perl oder Python. Solange die Datei nicht zu falsch ist, lesen Sie sie als Zeichenfolge in den Speicher und teilen Sie die Zeichenfolge auf. Wenn die Datei zu groß ist, ist mehr Arbeit erforderlich.
Faheem Mitha
@Faheem Mitha Die Datei ist 64MB groß. Ich mag die Idee, split zu verwenden, weil es schneller ist als das Schreiben von Code. Ich habe mich gefragt, ob ich bei Angabe der Zeilenanzahl, die 70% der Datei entspricht, eine große und eine kleine Datei erhalte. Sollte es nicht funktionieren?
aneuryzm
Und ja ... es hat funktioniert ... Soll ich die Frage löschen?
aneuryzm
Bis zu dir, aber nicht notwendig.
Faheem Mitha
Bitte teilen Sie Ihre Antwort. ( meta.stackexchange.com/questions/12513/… )
dogbane

Antworten:

13

Die folgenden Befehle funktionieren für Prozentsätze über 50% (wenn Sie nur in zwei Dateien aufteilen möchten), schnelles und unsauberes Vorgehen.

1) 70% basierend auf Linien aufgeteilt

split -l $[ $(wc -l filename|cut -d" " -f1) * 70 / 100 ] filename 

2) 70% basierend auf Bytes teilen

split -b $[ $(wc -c filename|cut -d" " -f1) * 70 / 100 ] filename
forcefsck
quelle
1
Unter MacOSX gibt wc manchmal die Anzahl der Zeilen mit einem Leerzeichen zurück, wodurch dieses Skript beschädigt wird. Erstes Piping zu xargs entfernt diese Leerzeichen und sorgt dafür, dass die Dinge wieder funktionieren: split -l $[ $(wc -l filename | xargs | cut -d" " -f1) * 70 / 100 ] filename
Emil Stenström
4

Sie können csplitbeispielsweise das erste Stück in zwei Teile teilen (mit einem beliebigen Prozentsatz) - die ersten 20% der Zeilen, das zweite Stück - die restlichen 80% der Zeilen:

csplit infile $(( $(wc -l < infile) * 2 / 10 + 1))

$(wc -l < infile): Gesamtzahl der Zeilen
2 / 10: Prozentsatz
+1: Fügen Sie eine Zeile hinzu, da sie sich csplitaufteiltup to but not including line N

Sie können jedoch nur anhand von Linien teilen.
Grundsätzlich können Sie, solange Sie die Zeilennummer über haben $(( $(wc -l < file) * 2 / 10)), jedes zeilenorientierte Werkzeug verwenden:

sed 1,$(( $(wc -l < infile) * 2 / 10))'{
w 20-infile
d
}' infile > 80-infile

oder noch cooler:

{ head -n$(( $(wc -l < infile) * 2 / 10)) > 20-infile; cat > 80-infile; } <infile

obwohl einige heads dumm sind und nicht den Standards entsprechen , funktioniert dies nicht bei allen Setups ...

don_crissti
quelle
2
{   BS=$(($(wc -c <file) * $P / 100))
    dd count=1 bs="$BS" >file1; cat
} <file >file2 2>/dev/null

... sollte in diesem einfachen Fall funktionieren, da Sie sich nur einmal aufteilen - und das ist wahrscheinlich splitein wenig übertrieben. Solange die Datei durchsuchbar ist, ddwird nur eine einzige tun read()auf <stdin, und so catbleibt seine beginnen read()um jeden Punkt ddverlässt es.

Wenn die Datei groß ist, wird a count=1 bs=$big_ol_nummöglicherweise etwas unhandlich und kann mit etwas zusätzlicher, aber einfacher Shell-Mathematik ausgeblendet werden.

Ein nicht-seekable Eingang - wie aus einem Rohr - könnte Skew dd's Ergebnisse, obwohl dies auch w / GNU gehandhabt werden kann , ddsind iflag=fullblock.

mikeserv
quelle
0

Der folgende Code verwendet headund tailfunktioniert mit jedem Verhältnis (in diesem Fall 40 bis 60):

export FILE_NAME=train.vw
head -n $[ $(wc -l ${FILE_NAME}|cut -d" " -f1) * 40 / 100 ] ${FILE_NAME} > train_40.vw
tail -n +$[ ($(wc -l ${FILE_NAME}|cut -d" " -f1) * 40 / 100) + 1 ] ${FILE_NAME} > train_60.vw
Alexandr Nikitin
quelle