Wie kann ich die Zeilen in einer Datei mit Standardtools unter Red Hat Linux zufällig sortieren?

102

Wie kann ich die Zeilen in einer Datei mit Standardtools unter Red Hat Linux zufällig sortieren?

Ich habe den shufBefehl nicht, also suche ich nach etwas wie einem perloder awkeinem Einzeiler, der die gleiche Aufgabe erfüllt.

Stuart Woodward
quelle
1
Ich habe fast die gleiche Frage gestellt [ stackoverflow.com/questions/286640/…
Steve Schnepp
Ich betrachte gcc als Standardwerkzeug unter jedem Linux. ; D
msb

Antworten:

63

Und einen Perl-Einzeiler bekommen Sie!

perl -MList::Util -e 'print List::Util::shuffle <>'

Es wird ein Modul verwendet, das Modul ist jedoch Teil der Perl-Codeverteilung. Wenn das nicht gut genug ist, können Sie erwägen, Ihre eigenen zu rollen.

Ich habe versucht, dies mit dem -iFlag ("Edit-in-Place") zu verwenden, damit die Datei bearbeitet wird. Die Dokumentation schlägt vor, dass es funktionieren sollte, aber es funktioniert nicht. Die gemischte Datei wird weiterhin in stdout angezeigt, diesmal wird jedoch das Original gelöscht. Ich schlage vor, Sie verwenden es nicht.

Betrachten Sie ein Shell-Skript:

#!/bin/sh

if [[ $# -eq 0 ]]
then
  echo "Usage: $0 [file ...]"
  exit 1
fi

for i in "$@"
do
  perl -MList::Util -e 'print List::Util::shuffle <>' $i > $i.new
  if [[ `wc -c $i` -eq `wc -c $i.new` ]]
  then
    mv $i.new $i
  else
    echo "Error for file $i!"
  fi
done

Ungetestet, funktioniert aber hoffentlich.

Chris Lutz
quelle
Um die Originaldatei zu sichern, können Sie dem Flag -i [ perldoc.perl.org/perlrun.html]
Steve Schnepp
Ich bin normalerweise ein Perl-Fan, bin aber auf dieses Rubin-Beispiel gestoßen, das den Vorteil hat, kürzer zu sein : ruby -e 'puts STDIN.readlines.shuffle'. Es müsste an großen Eingängen getestet werden, um festzustellen, ob die Geschwindigkeit vergleichbar ist. (funktioniert auch unter OS X)
Mivk
Laut Kommentar unten wird shufalles in den Speicher geladen, sodass es mit einer wirklich großen Datei nicht funktioniert (meine ist ~ 300 GB tsv). Dieses Perl-Skript ist auch bei mir fehlgeschlagen, aber ohne Fehler außer Killed. Irgendeine Idee, ob die Perl-Lösung auch alles in den Speicher lädt, oder gibt es ein anderes Problem, auf das ich stoße?
Seth127
211

Ähm, vergessen wir nicht

sort --random-sort
Jim T.
quelle
1
Nun, ich verwende gnu-coreutils 7.1 (Standard-Gentoo-Installation), das mit dieser Option sortiert ist. Ich bin mir nicht sicher, wann es angezeigt wurde oder ob es sich um eine andere Implementierung handelt.
Jim T
1
Die Funktion wurde am 10. Dezember 2005 festgeschrieben, die folgende Version war 5.94, ich vermute also, dass sie seit dieser Version verfügbar ist.
Jim T
41
Unter OS X können Sie gnu coreutils mit homebrew installieren: brew install coreutilsAllen Utils wird ag so vorangestellt: gsort --random-sortoder gshufsie funktionieren wie erwartet
mike
3
+1 @mike. Ich benutze Macports und ich hatte gsortund gshufinstallierte es auch, als ich es tatport install coreutils
Noah Sussman
9
Diese Lösung ist nur dann gut, wenn Ihre Zeilen keine Wiederholungen aufweisen. In diesem Fall werden alle Instanzen dieser Zeile nebeneinander angezeigt. Verwenden Sie shufstattdessen (unter Linux).
Ali J
117

shuf ist der beste Weg.

sort -Rist schmerzhaft langsam. Ich habe gerade versucht, 5 GB Datei zu sortieren. Ich gab nach 2,5 Stunden auf. Dann shufsortierte es in einer Minute.

Michal Illich
quelle
Das ist toll. Es scheint in GNU Coreutils zu sein.
Ariddell
4
Ich vermute, der Grund sort -Rdafür ist, dass für jede Zeile ein Hash berechnet wird. Aus den Dokumenten: " Sortieren durch Hashing der Eingabetasten und anschließendes Sortieren der Hashwerte. "
Joe Flynn
13
Vorsicht, shuflädt alles in den Speicher.
JFS
1
@benroth: Nach allem, was ich sagen kann, kann eine Erhöhung des Speichers bei sehr großen Eingaben etwas helfen , ist aber insgesamt immer noch langsam. In meinen Tests seq -f 'line %.0f' 1000000dauerte das Sortieren einer Eingabedatei mit 1 Million Zeilen, die mit erstellt wurde, dieselbe lange Zeit (viel, viel länger als mit shuf), unabhängig davon, wie viel Speicher ich zugewiesen habe.
mklement0
1
@ mklement0, du hast recht! Ich habe es gerade mit einer viel größeren Datei versucht als zuvor, und das Hashing scheint tatsächlich der Engpass zu sein.
Benroth
23
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Lesen Sie die Datei, stellen Sie jeder Zeile eine Zufallszahl voran, sortieren Sie die Datei nach diesen zufälligen Präfixen und schneiden Sie die Präfixe anschließend aus. Einzeiler, der in jeder halbmodernen Schale funktionieren sollte.

EDIT: Richard Hansens Bemerkungen aufgenommen.

ChristopheD
quelle
1
Dies funktioniert und ist eine kreative Lösung, löscht jedoch führende Leerzeichen in Zeilen.
Chris Lutz
@ Chris, der den letzten Schnitt in | sed 's / ^ [^ \ t] * \ t //'
ändert
Ein großes Lob an die Einfachheit des Ansatzes!
Shashikant Kore
3
+1 für POSIX-Konformität (außer $RANDOM), aber -1 für das Abschlachten der Daten. Durch Ersetzen while read fdurch while IFS= read -r fwird verhindert, readdass führende und nachfolgende Leerzeichen entfernt werden (siehe diese Antwort ) und die Verarbeitung von Backslashes verhindert wird. Durch die Verwendung einer zufälligen Zeichenfolge mit fester Länge wird verhindert, dass cutführende Leerzeichen gelöscht werden. Ergebnis: cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-
Richard Hansen
3
@ Richard Hansen: Danke, diese vorgeschlagenen Änderungen sind offensichtlich angemessen, ich habe meinen Beitrag bearbeitet.
ChristopheD
9

Ein Einzeiler für Python:

python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile

Und zum Drucken nur einer einzigen zufälligen Zeile:

python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile

Aber siehe diesen Beitrag für die Nachteile von Python random.shuffle(). Es funktioniert nicht gut mit vielen (mehr als 2080) Elementen.

scai
quelle
5

Bezogen auf Jims Antwort:

Mein ~/.bashrcenthält Folgendes:

unsort ()
{
    LC_ALL=C sort -R "$@"
}

Mit GNU coreutils 'sort, -R= --random-sort, das einen zufälligen Hash jeder Zeile generiert und danach sortiert. Der randomisierte Hash würde in einigen Gebietsschemas in einigen älteren (fehlerhaften) Versionen nicht verwendet, was dazu führt, dass er eine normal sortierte Ausgabe zurückgibt, weshalb ich ihn festgelegt habe LC_ALL=C.


Bezogen auf Chris 'Antwort:

perl -MList::Util=shuffle -e'print shuffle<>'

ist ein etwas kürzerer Einzeiler. ( -Mmodule=a,b,cist eine Abkürzung für-e 'use module qw(a b c);' .)

Der Grund dafür, dass das einfache -iMischen nicht funktioniert, ist, dass Perl erwartet, dass printdies in derselben Schleife geschieht, in der die Datei gelesen wird, undprint shuffle <> erst ausgegeben wird, nachdem alle Eingabedateien gelesen und geschlossen wurden.

Als kürzere Problemumgehung

perl -MList::Util=shuffle -i -ne'BEGIN{undef$/}print shuffle split/^/m'

mischt Dateien an Ort und Stelle. ( -nbedeutet "den Code in eine while (<>) {...}Schleife einschließen; BEGIN{undef$/}lässt Perl Dateien einzeln anstatt zeilenweise bearbeiten und split/^/mwird benötigt, weil $_=<>implizit mit einer gesamten Datei anstelle von Zeilen gearbeitet wurde.)

kurzlebig
quelle
Das Wiederholen dieser Sorte -R gibt es unter OS X nicht, aber +1 für einige großartige Perl-Antworten und eine großartige Antwort im Allgemeinen.
Chris Lutz
Sie könnten GNU-Coreutils unter OS X installieren, aber (wie ich es in der Vergangenheit getan habe) müssen Sie darauf achten, die integrierten Tools nicht zu beschädigen ... Abgesehen davon ist OP unter Redhat Linux, das definitiv GNU hat Coreutils Standard.
Ephemient
3

Wenn ich Coreutils mit Homebrew installiere

brew install coreutils

shufwird verfügbar als n.

John McDonnell
quelle
Brew hat allen Befehlen gso vorangestellt, dass es für mich so shufwurde gshuf.
Jörn
^ Liegt das daran, dass sie nicht POSIX sind, oder bin ich einfach total daneben?
Dave Liu
1

Mac OS X mit DarwinPorts:

sudo port install unsort
cat $file | unsort | ...
Coroos
quelle
1

FreeBSD hat ein eigenes zufälliges Dienstprogramm:

cat $file | random | ...

Es befindet sich in / usr / games / random. Wenn Sie also keine Spiele installiert haben, haben Sie kein Glück.

Sie können Ports wie textproc / rand oder textproc / msort installieren. Diese sind möglicherweise unter Linux und / oder Mac OS X verfügbar, wenn die Portabilität ein Problem darstellt.

Coroos
quelle
-1

Unter OSX das Neueste von http://ftp.gnu.org/gnu/coreutils/ und so ähnlich

./configure make sudo make install

... sollte Ihnen / usr / local / bin / sort --random-sort geben

ohne / usr / bin / sort durcheinander zu bringen

Dan Brickley
quelle
Dies funktionierte unter OSX (10.7) bei mir nicht. Ich habe "configure: error: C-Compiler kann keine ausführbaren Dateien erstellen".
Dolan Antenucci
@dolan Überprüfen Sie Ihre Berechtigungen?
Benubird
-1

Oder erhalten Sie es von MacPorts:

$ sudo port install coreutils

und / oder

$ /opt/local//libexec/gnubin/sort --random-sort
Chadwick Boggs
quelle