Ich habe eine Datenliste, wie
12345
23456
67891
-20000
200
600
20
...
Angenommen, die Größe dieses Datensatzes (dh der Dateizeilen) ist N
. Ich möchte zufällig m
Linien aus dieser Datendatei zeichnen . Daher sollte die Ausgabe aus zwei Dateien bestehen. Eine Datei enthält diese m
Datenzeilen und die andere enthält N-m
Datenzeilen.
Gibt es eine Möglichkeit, dies mit einem Linux-Befehl zu tun?
linux
shell
text-processing
user288609
quelle
quelle
Antworten:
Dies ist möglicherweise nicht der effizienteste Weg, funktioniert aber:
Mit
$m
enthält die Anzahl der Zeilen.quelle
sort -R
kümmert sich um die Zufälligkeit. Ich bin mir nicht sicher, ob Sie die Antwort dafür abgelehnt haben, aber schlagen Sie sie zuerst in der Manpage nach.sort -R
die Eingabe nicht genau zufällig sortiert wird: Sie gruppiert identische Zeilen. Also , wenn die Eingabe zBfoo
,foo
,bar
,bar
und m = 2, dann wird eine Datei enthalten beidefoo
s und die anderen beiden enthaltenbar
s. GNU Coreutils hat auchshuf
, die die Eingabezeilen randomisiert. Außerdem benötigen Sie keine temporäre Datei .shuf <file> |head -n $m
?Dieses Bash / Awk-Skript wählt Zeilen nach dem Zufallsprinzip aus und behält die ursprüngliche Reihenfolge in beiden Ausgabedateien bei.
Ausgabe, basierend auf den Daten in der Frage.
quelle
Wie bei allen Unix-Dingen gibt es ein Hilfsprogramm dafür TM .
Programm des Tages:
split
split
teilt eine Datei auf viele verschiedene Arten auf,-b
Bytes,-l
Zeilen,-n
Anzahl der Ausgabedateien. Wir werden die-l
Option nutzen. Da Sie nicht nur die erstenm
, sondern zufällige Zeilen auswählen möchten , wirdsort
die Datei zuerst in zufälliger Reihenfolge erstellt. Wenn Sie darüber lesen möchtensort
, beziehen Sie sich auf meine Antwort hier .Nun der eigentliche Code. Es ist eigentlich ganz einfach:
Dadurch werden zwei Dateien
m
mit denN-m
Namenoutput_prefixaa
und erstellt , eine mit Zeilen und eine mit Zeilenoutput_prefixab
. Stellen Sie sicher, dassm
es sich um die größere Datei handelt, ansonsten erhalten Sie mehrere Dateien mit der gewünschten Längem
(und eine mitN % m
).Wenn Sie sicherstellen möchten, dass Sie die richtige Größe verwenden, ist hier ein kleiner Code, um dies zu tun:
Edit: Es ist mir aufgefallen, dass einige
sort
Implementierungen kein-R
Flag haben. Wenn Sie habenperl
, können Sie ersetzenperl -e 'use List::Util qw/shuffle/; print shuffle <>;'
.quelle
sort -R
scheint das nur in einigen Versionen der Fall zu sein (wahrscheinlich die Gnu-Version). Für andere Plattformen habe ich ein Tool namens 'randline' geschrieben, das nichts anderes tut, als stdin zufällig zu machen. Es ist bei beesbuzz.biz/code für jeden, der es braucht. (Ich neige dazu, Dateiinhalt ziemlich viel zu mischen.)sort -R
die Eingabe nicht genau nach dem Zufallsprinzip sortiert wird: Sie gruppiert identische Zeilen. Also , wenn die Eingabe zBfoo
,foo
,bar
,bar
und m = 2, dann wird eine Datei enthalten beidefoo
s und die anderen beiden enthaltenbar
s. GNU Coreutils hat auchshuf
, die die Eingabezeilen randomisiert. Außerdem können Sie die Ausgabedateinamen , indem Sie wählenhead
undtail
stattsplit
.Wenn es Ihnen nichts ausmacht, die Zeilen neu zu ordnen, und Sie GNU-Coreutils haben (dh auf nicht eingebettetem Linux oder Cygwin, das seit
shuf
Version 6.0 nicht zu alt ist ),shuf
ordnet („shuffle“) die Zeilen einer Datei nach dem Zufallsprinzip neu. So können Sie die Datei mischen und die ersten m Zeilen in eine Datei und den Rest in eine andere Datei verschieben.Es gibt keine ideale Möglichkeit, diesen Versand durchzuführen. Man kann nicht einfach verketten
head
und würdetail
dahead
vorne puffern. Sie können verwendensplit
, aber Sie erhalten keine Flexibilität in Bezug auf die Ausgabedateinamen. Sie könnenawk
natürlich verwenden:Sie können verwenden
sed
, was für große Dateien unklar, aber möglicherweise schneller ist.Oder Sie können verwenden
tee
, um die Daten zu duplizieren, wenn Ihre Plattform hat/dev/fd
; das ist ok wenn m klein ist:Portabel können Sie awk verwenden, um jede Zeile der Reihe nach zu versenden. Beachten Sie, dass awk nicht sehr gut darin ist, seinen Zufallszahlengenerator zu initialisieren. Die Zufälligkeit ist nicht nur definitiv nicht für die Kryptographie geeignet, sondern auch nicht sehr gut für numerische Simulationen. Der Startwert ist für alle awk-Aufrufe auf jedem System in einem Zeitraum von einer Sekunde gleich.
Wenn Sie eine bessere Zufälligkeit benötigen, können Sie dasselbe in Perl tun, in dem der RNG-Wert ordnungsgemäß festgelegt wird.
quelle
awk
Beispiel:-v N=$(wc -l <file) -v m=4
... und es wird nur eine "zufällige" Zeile$m
gedruckt , wenn der Zufallswert kleiner als ist , anstatt$m
zufällige Zeilen zu drucken ... Es scheint,perl
als würde das mit rand dasselbe tun , aber ich ziehe an weiß nichtperl
gut genug, um einen Kompilierungsfehler zu überwinden: Syntaxfehler in -e Zeile 7, in der Nähe von ") print"shuf
Beispiel.head
cat
Kombination verursacht Datenverlust im folgenden zweiten Test 3-4 .... TEST 1-2{ for i in {00001..10000} ;do echo $i; done; } | { head -n 5000 >out1; cat >out2; }
.. TEST 3-4{ for i in {00001..10000} ;do echo $i; done; } >input; cat input | { head -n 5000 >out3; cat >out4; }
...wc -l
Ergebnisse für die Ausgaben von TEST 1-2 sind 5000 5000 (gut), aber für TEST 3-4 sind 5000 4539 Größen beteiligt ... Hier ist ein Link zu meinem (nicht gut) .. die differnece variiert je nach Datei Testcodehead
liest voraus; Was vorgelesen und nicht ausgedruckt wird, wird verworfen. Ich habe meine Antwort mit weniger eleganten, aber (da bin ich mir ziemlich sicher) richtigen Lösungen aktualisiert.Vorausgesetzt
m = 7
undN = 21
:Hinweis: Wenn Sie durch
7
eine Variable wie$1
oder ersetzen$m
, müssen Sieseq
nicht die{from..to}
-Notation verwenden, die keine Variablenerweiterung durchführt.Es funktioniert, indem Zeile für Zeile aus der Datei gelöscht wird, die immer kürzer wird, sodass die Zeilennummer, die entfernt werden kann, immer kleiner werden muss.
Dies sollte nicht für längere Dateien und viele Zeilen verwendet werden, da für jede Zahl im Durchschnitt die halbe Datei für den 1. und die gesamte Datei für den 2. sed- Code gelesen werden muss.
quelle
including them
aber auch die ursprünglichen Zeilen bedeuten - daherincluding
nichtconsisting of
und nicht benutzendonly
, aber ich denke, Ihre Interpretation ist, was user288609 bedeutete. Ich werde mein Skript entsprechend anpassen.+1
am falschen Ort.rnd=$((RANDOM%(N-i)+1))
In Ihrem Beispiel sollte N = 21 sein. Essed
stürzt derzeit ab , wennrnd
ausgewertet wird0
. Außerdem ist die Skalierung bei all dem Neuschreiben der Datei nicht sehr gut. Beispiel: 123 Sekunden , um 5.000 zufällige Zeilen aus einer 10.000-Zeilen-Datei zu extrahieren, gegenüber 0,03 Sekunden für eine direktere Methode ...