it-swarm.com.de

Wie kann ich die Zeilen einer Textdatei in der Unix-Befehlszeile oder in einem Shell-Skript mischen?

Ich möchte die Zeilen einer Textdatei nach dem Zufallsprinzip mischen und eine neue Datei erstellen. Die Datei kann mehrere tausend Zeilen enthalten.

Wie mache ich das mit cat, awk, cut usw.?

251

Sie können shuf verwenden. Zumindest auf einigen Systemen (scheint nicht in POSIX zu sein).

Wie Jleedev darauf hinwies: sort -R könnte auch eine Option sein. Zumindest auf einigen Systemen; Nun, du bekommst das Bild. Es wurde darauf hingewiesen , dass sort -R nicht wirklich mischt, sondern Elemente nach ihrem Hashwert sortiert.

[Anmerkung des Editors: sort -Rfast mischt, außer dass duplicate Zeilen/Sortierschlüssel immer nebeneinander stehen. Mit anderen Worten: Nur mit unique Eingabezeilen/Tasten ist es ein wahrer Zufall. Es ist zwar wahr, dass die Ausgabereihenfolge durch Hashwerte bestimmt wird, die Zufälligkeit ergibt sich jedoch aus der Wahl eines zufälligen Hashes Funktion - siehe manual .]

315
Joey

Perl-Einzeiler wäre eine einfache Version der Lösung von Maxim

Perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
77
Moonyoung Kang

Diese Antwort ergänzt die vielen großartigen vorhandenen Antworten auf folgende Weise:

  • Die vorhandenen Antworten sind in flexible Shell-Funktionen gepackt:

    • Die Funktionen nehmen nicht nur stdin Eingaben, sondern alternativ auch DateinameArgumente
    • Die Funktionen ergreifen zusätzliche Schritte, um SIGPIPE auf die übliche Weise zu behandeln (stille Beendigung mit Exit-Code 141), im Gegensatz zu lauten zu brechen. Dies ist wichtig, wenn die Funktionsausgabe an eine Pipe weitergeleitet wird, die vorzeitig geschlossen wird, z. B. wenn an head weitergeleitet wird.
  • Ein Leistungsvergleich wird durchgeführt.


  • POSIX-kompatible Funktion basierend auf awk, sort und cut, angepasst von OPs eigene Antwort :
shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print Rand(), $0}' "[email protected]" |
               sort -k1,1n | cut -d ' ' -f2-; }
shuf() { Perl -MList::Util=shuffle -e 'print shuffle(<>);' "[email protected]"; }
shuf() { python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;    
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];   
random.shuffle(lines); sys.stdout.write("".join(lines))
' "[email protected]"; }
shuf() { Ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
                     puts ARGF.readlines.shuffle' "[email protected]"; }

Leistungsvergleich:

Hinweis: Diese Zahlen wurden auf einem iMac von Ende 2012 mit 3,2 GHz Intel Core i5 und einem Fusion-Laufwerk unter OSX 10.10.3 ermittelt. Während das Timing mit dem verwendeten Betriebssystem, den Maschinenspezifikationen und der verwendeten awk -Implementierung variiert (z. B. der verwendeten BSD awk -Version) unter OSX ist es normalerweise langsamer als GNU awk und insbesondere mawk), dies sollte einen allgemeinen Sinn für relativeperformance .

Eingabedatei ist eine 1-Millionen-Zeilen-Datei , die mit seq -f 'line %.0f' 1000000.
Die Zeiten sind in aufsteigender Reihenfolge aufgeführt (schnellste zuerst):

  • shuf
    • 0.090s
  • Ruby 2.0.0
    • 0.289s
  • Perl 5.18.2
    • 0.589s
  • Python
    • 1.342s mit Python 2.7.6; 2.407s (!) mit Python 3.4.2
  • awk + sort + cut
    • 3.003s mit BSD awk; 2.388s mit GNU awk (4.1.1); 1.811s mit mawk (1.3.4);

Zum weiteren Vergleich sind die Lösungen, die nicht als Funktionen verpackt sind, wie folgt:

  • sort -R (kein wahres Mischen, wenn es doppelte Eingabezeilen gibt)
    • 10.661s - Die Zuweisung von mehr Speicher scheint keinen Unterschied zu machen
  • Scala
    • 24.229s
  • bash Schleifen + sort
    • 32.593s

Schlussfolgerungen :

  • Verwenden Sie shuf, wenn Sie können - es ist bei weitem das schnellste.
  • Ruby macht sich gut, gefolgt von Perl .
  • Python ist merklich langsamer als Ruby und Perl, und im Vergleich Python= Versionen , 2.7.6 ist viel schneller als 3.4.1
  • Verwenden Sie die POSIX-kompatible Kombination awk + sort + cut als letzten Ausweg ; Welche awk Implementierung Sie verwenden, ist von Bedeutung (mawk ist schneller als GNU awk, BSD awk ist am langsamsten).
  • Bleiben Sie weg von sort -R, bash Schleifen und Scala.
57
mklement0

Ich benutze ein kleines Perl-Skript, das ich "unsortieren" nenne:

#!/usr/bin/Perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);

Ich habe auch eine NULL-begrenzte Version namens "unsort0" ... praktisch für die Verwendung mit find -print0 und so weiter.

PS: Ich habe auch 'shuf' gewählt, ich hatte keine Ahnung, dass es heutzutage in coreutils war ... das oben genannte kann immer noch nützlich sein, wenn Ihr System nicht 'shuf' hat.

27
NickZoic

Hier ist ein erster Versuch, der für den Codierer einfach ist, aber hart für die CPU, die jeder Zeile eine Zufallszahl voranstellt, sie sortiert und dann die Zufallszahl aus jeder Zeile entfernt. Tatsächlich werden die Zeilen zufällig sortiert:

cat myfile | awk 'BEGIN{srand();}{print Rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
17

hier ist ein awk-script

awk 'BEGIN{srand() }
{ lines[++d]=$0 }
END{
    while (1){
    if (e==d) {break}
        RANDOM = int(1 + Rand() * d)
        if ( RANDOM in lines  ){
            print lines[RANDOM]
            delete lines[RANDOM]
            ++e
        }
    }
}' file

ausgabe

$ cat file
1
2
3
4
5
6
7
8
9
10

$ ./Shell.sh
7
5
10
9
6
8
2
1
3
4
16
ghostdog74

Ein Liner für Python:

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

Und um nur eine einzige zufällige Zeile zu drucken:

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

Aber siehe diesen Beitrag für die Nachteile von Pythons random.shuffle(). Mit vielen (mehr als 2080) Elementen funktioniert es nicht gut.

11
scai

Eine einfache, auf AWS basierende Funktion erledigt die Arbeit:

shuffle() { 
    awk 'BEGIN{srand();} {printf "%06d %s\n", Rand()*1000000, $0;}' | sort -n | cut -c8-
}

verwendungszweck:

any_command | shuffle

Dies sollte auf fast jedem UNIX funktionieren. Getestet unter Linux, Solaris und HP-UX.

Update:

Beachten Sie, dass die Multiplikation führender Nullen (%06d) und Rand() es auch auf Systemen ermöglicht, auf denen sort Zahlen nicht versteht. Es kann über die lexikografische Reihenfolge sortiert werden (auch normaler Vergleich von Strings).

8
Michał Šrajer

Ruby FTW:

ls | Ruby -e 'puts STDIN.readlines.shuffle'
7
hoffmanc

Ein Liner für Python basierend auf scais Antwort , aber a) nimmt stdin, b) macht das Ergebnis mit Seed wiederholbar, c) wählt nur 200 von allen Zeilen aus.

$ cat file | python -c "import random, sys; 
  random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
  > 200lines.txt
6
dfrankow

Ein einfacher und intuitiver Weg wäre die Verwendung von shuf.

Beispiel:

Angenommen, words.txt als:

the
an
linux
ubuntu
life
good
breeze

Mischen Sie die Zeilen wie folgt:

$ shuf words.txt

das würde die gemischten Zeilen nach Standardausgabe werfen; Also müssen Sie Pipe zu einer Ausgabedatei wie folgt:

$ shuf words.txt > shuffled_words.txt

Ein solcher Shuffle Run könnte ergeben:

breeze
the
linux
an
ubuntu
good
life
4
kmario23

Wir haben ein Paket, um den Job zu erledigen: 

Sudo apt-get install randomize-lines

Beispiel:

Erstellen Sie eine geordnete Liste von Nummern und speichern Sie sie in 1000.txt: 

seq 1000 > 1000.txt

um es zu mischen, verwenden Sie einfach 

rl 1000.txt
4
navigaid

Wenn Sie wie ich hierher gekommen sind, um nach einer Alternative zu shuf für macOS zu suchen, verwenden Sie randomize-lines.

Installieren Sie das Paket randomize-lines (homebrew), das einen rl-Befehl mit ähnlicher Funktionalität wie shuf enthält.

brew install randomize-lines

Usage: rl [OPTION]... [FILE]...
Randomize the lines of a file (or stdin).

  -c, --count=N  select N lines from the file
  -r, --reselect lines may be selected multiple times
  -o, --output=FILE
                 send output to file
  -d, --delimiter=DELIM
                 specify line delimiter (one character)
  -0, --null     set line delimiter to null character
                 (useful with find -print0)
  -n, --line-number
                 print line number with output lines
  -q, --quiet, --silent
                 do not output any errors or warnings
  -h, --help     display this help and exit
  -V, --version  output version information and exit
3
Ahmad Awais

Dies ist ein Python-Skript, das ich als Rand.py in meinem Home-Ordner gespeichert habe:

#!/bin/python

import sys
import random

if __== '__main__':
  with open(sys.argv[1], 'r') as f:
    flist = f.readlines()
    random.shuffle(flist)

    for line in flist:
      print line.strip()

Unter Mac OSX sind sort -R und shuf nicht verfügbar. Sie können dies in Ihrem bash_profile als Alias ​​angeben:

alias shuf='python Rand.py'
3
Jeff Wu

Wenn Sie Scala installiert haben, können Sie die Eingabe mit einem Einzeiler mischen:

ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
2
swartzrock

Diese bash-Funktion hat die minimale Abhängigkeit (nur sort und bash):

shuf() {
while read -r x;do
    echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
    echo $y
done
}
1
Meow

Noch nicht erwähnt:

  1. Die unsort util. Syntax (etwas Playlist-orientiert):

    unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
           [--identity] [--filenames[=profile]] [--separator sep] [--concatenate] 
           [--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null] 
           [--linefeed] [file ...]
    
  2. msort kann mischen, aber normalerweise ist es übertrieben:

    seq 10 | msort -jq -b -l -n 1 -c r
    
0
agc

Eine andere awk Variante:

#!/usr/bin/awk -f
# usage:
# awk -f randomize_lines.awk lines.txt
# usage after "chmod +x randomize_lines.awk":
# randomize_lines.awk lines.txt

BEGIN {
  FS = "\n";
  srand();
}

{
  lines[ Rand()] = $0;
}

END {
  for( k in lines ){
    print lines[k];
  }
}
0
biziclop

In Windows können Sie versuchen, diese Batchdatei , um Ihre Daten zu mischen.txt. Die Verwendung des Batchcodes ist

C:\> type list.txt | shuffle.bat > maclist_temp.txt

Nachdem Sie diesen Befehl ausgegeben haben, enthält maclist_temp.txt eine randomisierte Liste von Zeilen.

Hoffe das hilft.

0
Ayfan