Was ist eine einfache Möglichkeit, zufällige Zeilen aus einer Datei in der Unix-Befehlszeile zu lesen?
linux
unix
random
command-line
Codeforester
quelle
quelle
Antworten:
Sie können verwenden
shuf
:Es gibt auch ein Dienstprogramm namens
rl
. In Debian ist es imrandomize-lines
Paket enthalten, das genau das tut, was Sie wollen, obwohl es nicht in allen Distributionen verfügbar ist. Auf seiner Homepage empfiehlt es tatsächlich die Verwendung vonshuf
stattdessen (was meiner Meinung nach nicht existierte, als es erstellt wurde).shuf
ist Teil der GNU Coreutils,rl
nicht.quelle
shuf
Tipp, es ist in Fedora integriert.sort -R
wird auf jeden Fall viel warten lassen, wenn es sich um sehr große Dateien handelt - 80kk Zeilen -, während esshuf -n
ziemlich augenblicklich funktioniert .coreutils
von Homebrew installieren . Könntegshuf
statt genannt werdenshuf
.randomize-lines
unter OS X vonbrew install randomize-lines; rl -c 1 $FILE
shuf
Teil von GNU Coreutils ist und daher nicht unbedingt (standardmäßig) auf * BSD-Systemen (oder Mac?) Verfügbar ist. Der Perl-Einzeiler von @ Tracker1 unten ist portabler (und nach meinen Tests etwas schneller).Eine andere Alternative:
quelle
(${RANDOM} << 15) + ${RANDOM}
. Dies reduziert die Verzerrung erheblich und ermöglicht es, für Dateien mit bis zu 1 Milliarde Zeilen zu arbeiten.+
und|
sind gleich, da${RANDOM}
per Definition 0..32767 ist.(Ich mag den Shuf-Ansatz oben noch besser - ich wusste nicht einmal, dass es ihn gibt und ich hätte dieses Tool alleine nie gefunden)
quelle
sort
, die auf keinem meiner Systeme funktioniert hat (CentOS 5.5, Mac OS 10.7.2). Auch nutzloser Gebrauch von Katze, könnte aufsort --random-sort < $FILE | head -n 1
sort -R <<< $'1\n1\n2' | head -1
ist ebenso wahrscheinlich, 1 und 2 zurückzugeben, dasort -R
doppelte Zeilen zusammen sortiert werden. Gleiches giltsort -Ru
, weil dadurch doppelte Zeilen entfernt werden.sort
vor dem Weiterleiten gemischt werden musshead
.shuf
wählt stattdessen zufällige Zeilen aus der Datei aus und ist für mich viel schneller.sort --random-sort $FILE | head
wäre am besten, da es ihm ermöglicht, direkt auf die Datei zuzugreifen, was möglicherweise eine effiziente parallele Sortierung ermöglicht--random-sort
und-R
sind spezifisch für die GNU-Sortierung (daher funktionieren sie nicht mit BSD oder Mac OSsort
). GNU sort hat diese Flags im Jahr 2005 gelernt, sodass Sie GNU Coreutils 6.0 oder neuer (z. B. CentOS 6) benötigen.Das ist einfach.
Zugegeben, dies ist nur ein bisschen langsamer als die "shuf -n 1 file.txt" für sich.
quelle
-n 1
1 Zeile angegeben ist und Sie diese in mehr als 1 ändern können.shuf
Kann auch für andere Zwecke verwendet werden. Ich habe gerade gepfeiftps aux
undgrep
damit zufällig Prozesse beendet, die teilweise mit einem Namen übereinstimmen.perlfaq5: Wie wähle ich eine zufällige Zeile aus einer Datei aus? Hier ist ein Reservoir-Sampling-Algorithmus aus dem Camel Book:
Dies hat einen erheblichen räumlichen Vorteil gegenüber dem Einlesen der gesamten Datei. Einen Beweis für diese Methode finden Sie in The Art of Computer Programming, Band 2, Abschnitt 3.4.2, von Donald E. Knuth.
quelle
shuf
. Der Perl-Code ist etwas schneller (8% schneller nach Benutzerzeit, 24% schneller nach Systemzeit), obwohl ich anekdotisch festgestellt habe, dass der Perl-Code weniger zufällig "scheint" (ich habe eine Jukebox damit geschrieben).shuf
Speichert die gesamte Eingabedatei im Speicher , was eine schreckliche Idee ist, während dieser Code nur eine Zeile speichert, sodass die Grenze dieses Codes eine Zeilenanzahl von INT_MAX ist (2 ^ 31 oder 2 ^ 63, abhängig von Ihrer arch), unter der Annahme, dass eine der ausgewählten potenziellen Linien in den Speicher passt.Verwenden eines Bash-Skripts:
quelle
Einzelne Bash-Linie:
Leichtes Problem: doppelter Dateiname.
quelle
wc -l < test.txt
vermeidet das Weiterleitencut
.Hier ist ein einfaches Python-Skript, das die Arbeit erledigt:
Verwendungszweck:
quelle
import random, sys lines = open(sys.argv[1]).readlines()
Folgendes getan: für i im Bereich (len (Linien)): rand = random.randint (0, len (Linien) -1) print lines.pop (rand),len(lines)
kann daher zu IndexError führen. Sie könnten verwendenprint(random.choice(list(open(sys.argv[1]))))
. Es gibt auch einen speichereffizienten Reservoir-Abtastalgorithmus .Ein anderer Weg mit ' awk '
quelle
$RANDOM
ist ein Bashismus ). Hier ist eine reine awk (mawk) -Methode, die dieselbe Logik wie der oben zitierte Perlfaq5-Code von @ Tracker1 verwendet:awk 'rand() * NR < 1 { line = $0 } END { print line }' file.name
(Wow, es ist sogar noch kürzer als der Perl-Code!)wc
) lesen , um eine Zeilenanzahl zu erhalten, und muss dann (einen Teil) der Datei erneut lesen (awk
), um den Inhalt der angegebenen zufälligen Zeilennummer zu erhalten. E / A sind weitaus teurer als das Erhalten einer Zufallszahl. Mein Code liest die Datei nur einmal. Das Problem bei awk'srand()
ist, dass es auf Sekunden basiert, sodass Sie Duplikate erhalten, wenn Sie es nacheinander zu schnell ausführen.Eine Lösung, die auch unter MacOSX funktioniert und auch unter Linux (?) Funktionieren sollte:
Wo:
N
ist die Anzahl der gewünschten zufälligen ZeilenNR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2
-> Speichern Sie die eingegebenen Zeilennummernfile1
und drucken Sie die entsprechende Zeile einfile2
jot -r $N 1 $(wc -l < $file)
->N
Zahlen zufällig (-r
) im Bereich(1, number_of_line_in_file)
mit zeichnenjot
. Durch die Prozessersetzung<()
sieht es wie eine Datei für den Interpreter aus, alsofile1
im vorherigen Beispiel.quelle
quelle
Folgendes entdecke ich, da mein Mac OS nicht alle einfachen Antworten verwendet. Ich habe den Befehl jot verwendet, um eine Zahl zu generieren, da die variablen Lösungen von $ RANDOM in meinem Test nicht sehr zufällig zu sein scheinen. Beim Testen meiner Lösung gab es große Unterschiede bei den in der Ausgabe angegebenen Lösungen.
Das Echo der Variablen dient dazu, eine visuelle Darstellung der generierten Zufallszahl zu erhalten.
quelle
Wenn Sie nur Vanille sed und awk verwenden und $ RANDOM nicht verwenden, ist ein einfacher, platzsparender und relativ schneller "Einzeiler" zum Auswählen einer einzelnen Zeile pseudozufällig aus einer Datei mit dem Namen FILENAME wie folgt:
(Dies funktioniert auch, wenn FILENAME leer ist. In diesem Fall wird keine Zeile ausgegeben.)
Ein möglicher Vorteil dieses Ansatzes besteht darin, dass rand () nur einmal aufgerufen wird.
Wie von @AdamKatz in den Kommentaren hervorgehoben, besteht eine andere Möglichkeit darin, rand () für jede Zeile aufzurufen:
(Ein einfacher Korrektheitsnachweis kann auf der Grundlage der Induktion erbracht werden.)
Vorbehalt über
rand()
"In den meisten awk-Implementierungen, einschließlich gawk, generiert rand () jedes Mal, wenn Sie awk ausführen, Zahlen aus derselben Startnummer oder demselben Startwert."
- https://www.gnu.org/software/gawk/manual/html_node/Numeric-Functions.html
quelle