Comment puis-je mélanger les lignes d'un fichier texte sur la ligne de commande Unix ou dans un script shell?

je veux battre les lignes d'un fichier texte au hasard et créer un nouveau fichier. Le fichier peut avoir plusieurs milliers de lignes.

Comment puis-je faire cela avec cat , awk , cut , etc?

240
demandé sur Gioconda 2010-01-28 13:49:08

19 réponses

vous pouvez utiliser shuf . Sur certains systèmes au moins (ne semble pas être en POSIX).

comme jleedev a souligné: sort -R pourrait également être une option. Sur certains systèmes, au moins; eh bien, vous obtenez l'image. il a été souligné que sort -R ne mélange pas vraiment mais trie les articles en fonction de leur valeur de hachage.

[ndlr: sort -R presque shuffles, sauf que dupliquer lignes / tri clés toujours finir par à côté de l'autre . En d'autres termes: ce n'est qu'avec unique lignes d'entrée / clés est un vrai mélange. Alors qu'il est vrai que l'ordre de sortie est déterminée par valeurs de hachage , le caractère aléatoire vient du choix d'un hachage aléatoire fonction - voir manuel .]

299
répondu Joey 2017-05-23 10:31:36

Perl one-liner serait une version simple de la solution de Maxim

perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
76
répondu Moonyoung Kang 2016-09-18 19:30:03

cette réponse complète les nombreuses grandes réponses existantes de la manière suivante:

  • les réponses existantes sont emballé dans flexible fonctions de coque :

    • Les fonctions non seulement "151940920 d'entrée", mais sinon aussi nom de fichier arguments
    • le fonctions prendre des mesures supplémentaires pour gérer SIGPIPE de la manière habituelle (terminaison calme avec le code de sortie 141 ), par opposition à briser bruyamment. Cela est important lorsque la tuyauterie de la sortie de la fonction à un tuyau qui est fermé tôt, comme lorsque la tuyauterie à head .
  • Un comparaison des performances .


  • fonction conforme à POSIX basée sur awk , sort , et cut , adapté de la OP's own answer :
shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), " 151900920"}' "$@" |
               sort -k1,1n | cut -d ' ' -f2-; }
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
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))
' "$@"; }
shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
                     puts ARGF.readlines.shuffle' "$@"; }

comparaison des performances:

Note: ces nombres étaient obtenu sur un iMac fin 2012 avec un Intel i5 de 3,2 GHz et un lecteur de Fusion, tournant OSX 10.10.3. alors que le timing varie avec L'OS utilisé, les spécifications de la machine, awk implémentation utilisée (par exemple, la version BSD awk utilisée sur OSX est généralement plus lente que GNU awk et surtout mawk ), ceci devrait fournir un sens général de relatif performance .

Le fichier d'entrée est un fichier de 1 million de lignes produit avec seq -f 'line %.0f' 1000000 .

Les temps sont énumérés dans l'ordre croissant (le plus rapide en premier):

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

pour comparaison ultérieure, les solutions non emballées en fonction ci-dessus:

  • sort -R (ce n'est pas un vrai shuffle s'il y a des lignes d'entrée dupliquées)
    • 10.661s - allouer plus de mémoire ne semble pas faire de différence
  • Scala
    • 24.229s
  • bash boucles + sort
    • 32.593s

Conclusions :

  • utilisez shuf , si vous can - c'est de loin le plus rapide.
  • Ruby fait bien, suivi par Perl .
  • Python est nettement plus lent que Ruby et Perl, et, en comparant les versions de Python, 2.7.6 est un peu plus rapide que 3.4.1
  • awk + sort + cut combo en dernier recours ; qui awk implémentation que vous utilisez matters ( mawk est plus rapide que GNU awk , BSD awk est plus lent).
  • Rester à l'écart de sort -R , bash les boucles et la Scala.
49
répondu mklement0 2017-05-23 12:26:33

j'utilise un petit script perl, que j'appelle "unsort":

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

j'ai aussi une version nulle, appelée" unsort0"... pratique pour une utilisation avec trouver -print0 et ainsi de suite.

PS: voté 'shuf' aussi, je n'avais aucune idée qui était là à coreutils ces jours-ci ... le ci-dessus peut encore être utile si vos systèmes n'ont pas 'chouf'.

27
répondu NickZoic 2010-01-28 13:10:13

voici un premier essai qui est facile sur le codeur mais dur sur le CPU qui prépose un nombre aléatoire à chaque ligne, les trie et puis coupe le nombre aléatoire de chaque ligne. En effet, les lignes sont triées au hasard:

cat myfile | awk 'BEGIN{srand();}{print rand()"\t""151900920"}' | sort -k1 -n | cut -f2- > myfile.shuffled
17
répondu Ruggiero Spearman 2010-01-28 10:50:47

voici un script awk

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

sortie

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

$ ./shell.sh
7
5
10
9
6
8
2
1
3
4
15
répondu ghostdog74 2010-01-28 11:29:35

Un one-liner pour python:

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

et pour l'impression d'une seule ligne au hasard:

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

Mais voir ce post pour les inconvénients de python random.shuffle() . Il ne fonctionnera pas bien avec beaucoup d'éléments (plus de 2080).

9
répondu scai 2017-05-23 12:10:47

Simple awk fonction sera de faire le travail:

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

utilisation:

any_command | shuffle

cela devrait fonctionner sur presque n'importe quel UNIX. Testé sur Linux, Solaris et HP-UX.

mise à jour:

Note, que la multiplication des zéros de tête ( %06d ) et rand() le fait fonctionner correctement aussi sur les systèmes où sort ne comprend pas les nombres. Il peut être triée par ordre lexicographique(A. K. A. comparaison de chaîne normale).

8
répondu Michał Šrajer 2015-05-08 13:00:07

Ruby FTW:

ls | ruby -e 'puts STDIN.readlines.shuffle'
7
répondu hoffmanc 2014-12-16 16:43:36

une doublure pour Python basée sur la réponse de scai , mais a) prend stdin, b) rend le résultat reproductible avec seed, c) choisit seulement 200 de toutes les lignes.

$ cat file | python -c "import random, sys; 
  random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
  > 200lines.txt
6
répondu dfrankow 2017-05-23 11:47:29

c'est un script python que j'ai enregistré comme rand.py dans mon dossier personnel:

#!/bin/python

import sys
import random

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

    for line in flist:
      print line.strip()

Sur Mac OSX sort -R et shuf ne sont pas disponibles de sorte que vous pouvez alias dans votre bash_profile:

alias shuf='python rand.py'
3
répondu Jeff Wu 2013-07-11 17:48:43

nous avons un paquet pour faire le travail:

sudo apt-get install randomize-lines

exemple:

créez une liste ordonnée de numéros, et sauvegardez-la à 1000.txt:

seq 1000 > 1000.txt

à battre, il suffit d'utiliser

rl 1000.txt
3
répondu navigaid 2016-09-11 14:46:34

si comme moi vous êtes venu ici pour chercher une alternative à shuf pour macOS puis utiliser randomize-lines .

Installer randomize-lines (homebrew), qui a un "151940920 de la commande" qui a des fonctionnalités similaires à shuf .

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
répondu Ahmad Awais 2017-02-05 19:21:05

une façon simple et intuitive serait d'utiliser shuf .

exemple:

supposer words.txt comme:

the
an
linux
ubuntu
life
good
breeze

Pour brouiller les lignes, faire:

$ shuf words.txt

qui lancerait les lignes mélangées à sortie standard ; donc, vous avez à pipe il à un fichier de sortie like:

$ shuf words.txt > shuffled_words.txt

l'Un de ces shuffle run pourrait donner:

breeze
the
linux
an
ubuntu
good
life
2
répondu kmario23 2018-03-09 02:26:11

si vous avez Scala installé, voici une doublure pour mélanger l'entrée:

ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
1
répondu swartzrock 2014-06-20 12:37:43

cette fonction bash a la dépendance minimale (seulement sort et 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
répondu Meow 2015-01-22 03:34:21

sous windows, vous pouvez essayer ce fichier de lots pour vous aider à mélanger vos données.txt, l'utilisation du code de lot est

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

après l'émission de cette commande, maclist_temp.txt contient une liste aléatoire de lignes.

Espérons que cette aide.

0
répondu Ayfan 2014-04-27 21:20:07

pas encore mentionné:

  1. Le unsort util. Syntaxe (plutôt orientée playlist):

    unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
           [--identity] [--filenames[=profile]] [--separator sep] [--concatenate] 
           [--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null] 
           [--linefeed] [file ...]
    
  2. msort

    seq 10 | msort -jq -b -l -n 1 -c r
    
0
répondu agc 2017-04-17 16:52:13

une autre 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()] = "151900920";
}

END {
  for( k in lines ){
    print lines[k];
  }
}
0
répondu biziclop 2017-12-01 13:33:08