Comment puis-je randomiser les lignes d'un fichier à l'aide d'outils standard sur Red Hat Linux?

102

Comment puis-je randomiser les lignes d'un fichier à l'aide d'outils standard sur Red Hat Linux?

Je n'ai pas la shufcommande, donc je recherche quelque chose comme un perlou awkune ligne qui accomplit la même tâche.

Stuart Woodward
la source
1
J'ai posé presque la même question [ stackoverflow.com/questions/286640/…
Steve Schnepp
Je considère gcc comme un outil standard dans n'importe quel Linux. ; D
msb

Réponses:

64

Et vous obtenez un one-liner Perl!

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

Il utilise un module, mais le module fait partie de la distribution de code Perl. Si ce n'est pas suffisant, vous pouvez envisager de rouler le vôtre.

J'ai essayé de l'utiliser avec le -idrapeau ("edit-in-place") pour qu'il modifie le fichier. La documentation suggère que cela devrait fonctionner, mais ce n'est pas le cas. Il affiche toujours le fichier mélangé vers stdout, mais cette fois, il supprime l'original. Je vous suggère de ne pas l'utiliser.

Considérez un script shell:

#!/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

Non testé, mais je l'espère fonctionne.

Chris Lutz
la source
Pour sauvegarder le fichier d'origine, vous pouvez ajouter
Steve Schnepp
Je suis habituellement un fan Perl, mais suis tombé sur cet exemple de rubis qui a l'avantage d'être plus courte: ruby -e 'puts STDIN.readlines.shuffle'. Il faudrait des tests sur de grosses entrées pour voir si la vitesse est comparable. (fonctionne aussi sur OS X)
mivk
par commentaire ci-dessous, shufcharge tout en mémoire, donc cela ne fonctionne pas avec un fichier vraiment énorme (le mien est ~ 300 Go tsv). Ce script perl a également échoué sur le mien, mais sans erreur sauf Killed. Une idée si la solution perl charge également tout en mémoire, ou y a-t-il un autre problème que je rencontre?
seth127
211

Um, n'oublions pas

sort --random-sort
Jim T
la source
1
Eh bien, j'utilise gnu-coreutils 7.1 (installation standard de gentoo), qui a un tri avec cette option, je ne sais pas quand elle est apparue, ou si c'est dans d'autres implémentations.
Jim T
1
La fonctionnalité a été validée le 10 décembre 2005, la version suivante était la 5.94, donc je suppose qu'elle est disponible depuis cette version.
Jim T
41
Sur OS X , vous pouvez installer gnu coreutils avec homebrew: brew install coreutilsTous les utils sont préfixées avec ag donc: gsort --random-sortou gshuffonctionnera comme prévu
mike
3
+1 @mike. J'utilise Macports et j'ai aussi eu gsortet gshufinstallé quand je l'ai faitport install coreutils
Noah Sussman
10
Cette solution n'est bonne que si vos lignes n'ont pas de répétitions. Si tel est le cas, toutes les instances de cette ligne apparaîtront les unes à côté des autres. Pensez à utiliser à la shufplace (sous Linux).
Ali J
118

shuf est le meilleur moyen.

sort -Rest douloureusement lent. J'ai juste essayé de trier le fichier de 5 Go. J'ai abandonné après 2,5 heures. Puis shuftrié en une minute.

Michal Illich
la source
C'est bien. Il semble que ce soit dans GNU coreutils.
ariddell
4
Je soupçonne que la raison sort -Rest lente est que calcule un hachage pour chaque ligne. À partir de la documentation: " Trier en hachant les clés d'entrée, puis en triant les valeurs de hachage. "
Joe Flynn
13
attention, shufcharge tout en mémoire.
jfs
1
@benroth: D'après ce que je peux dire, avec un très grand nombre d'entrées, augmenter la mémoire peut aider un peu , mais c'est toujours lent dans l'ensemble. Dans mes tests, le tri d' un fichier d'entrée de 1 million de ligne créée avec seq -f 'line %.0f' 1000000a la même, à long temps de processus (beaucoup, beaucoup plus qu'avec shuf), peu importe la quantité de mémoire que j'alloué.
mklement0
1
@ mklement0, vous avez raison! Je l'ai juste essayé avec un fichier beaucoup plus gros que ce que j'avais auparavant, et le hachage semble être le goulot d'étranglement.
benroth
23
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Lisez le fichier, ajoutez un nombre aléatoire à chaque ligne, triez le fichier sur ces préfixes aléatoires, coupez les préfixes par la suite. Une doublure qui devrait fonctionner dans n'importe quelle coque semi-moderne.

EDIT: a incorporé les remarques de Richard Hansen.

ChristopheD
la source
1
Cela fonctionne, et est une solution créative, mais supprimera les espaces de début sur les lignes.
Chris Lutz
@Chris en changeant la dernière coupe en | sed 's / ^ [^ \ t] * \ t //' devrait corriger cela
bdonlan
Bravo à la simplicité de l'approche!
Shashikant Kore
3
+1 pour la conformité POSIX (sauf pour $RANDOM), mais -1 pour le dépeçage des données. Le remplacement while read fpar while IFS= read -r fempêchera readde supprimer les espaces de début et de fin (voir cette réponse ) et empêchera le traitement des contre-obliques. L'utilisation d'une chaîne aléatoire de longueur fixe empêchera cutde supprimer les espaces de début. Résultat: cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-
Richard Hansen du
3
@Richard Hansen: Merci, ces modifications suggérées sont évidemment appropriées, j'ai édité mon message.
ChristopheD
9

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 imprimer une seule ligne aléatoire:

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

Mais voyez cet article pour les inconvénients de python random.shuffle(). Cela ne fonctionnera pas bien avec de nombreux éléments (plus de 2080).

scai
la source
5

Lié à la réponse de Jim:

My ~/.bashrccontient les éléments suivants:

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

Avec le tri de GNU coreutils, -R= --random-sort, qui génère un hachage aléatoire de chaque ligne et trie par elle. Le hachage aléatoire ne serait pas réellement utilisé dans certains paramètres régionaux dans certaines versions plus anciennes (boguées), ce qui le fait renvoyer une sortie triée normale, c'est pourquoi j'ai défini LC_ALL=C.


Lié à la réponse de Chris:

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

est une doublure un peu plus courte. ( -Mmodule=a,b,cest un raccourci pour -e 'use module qw(a b c);'.)

La raison pour laquelle donner un simple -ine fonctionne pas pour la lecture aléatoire sur place est que Perl s'attend à ce que cela printse produise dans la même boucle que le fichier est en cours de lecture, et print shuffle <>ne sortira qu'après que tous les fichiers d'entrée aient été lus et fermés.

En guise de solution de contournement plus courte,

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

va mélanger les fichiers sur place. ( -nsignifie "envelopper le code dans une while (<>) {...}boucle; BEGIN{undef$/}fait en sorte que Perl opère sur des fichiers à la fois au lieu de lignes à la fois, et split/^/mest nécessaire car cela $_=<>a été implicitement fait avec un fichier entier au lieu de lignes.)

éphémère
la source
Réitérant que le tri -R n'existe pas sous OS X, mais +1 pour quelques bonnes réponses Perl, et une excellente réponse en général.
Chris Lutz
Vous pouvez installer GNU coreutils sur OS X, mais (comme je l'ai fait dans le passé) vous devez faire attention à ne pas casser les outils intégrés ... Cela étant dit, OP est sur Redhat Linux, qui a définitivement GNU norme coreutils.
éphémère
3

Quand j'installe coreutils avec homebrew

brew install coreutils

shufdevient disponible en tant que n.

John McDonnell
la source
Brew a préfixé toutes les commandes avec gainsi shufdevenu gshufpour moi.
Jörn
^ Est-ce parce qu'ils ne sont pas POSIX, ou est-ce que je suis tout simplement hors de propos?
Dave Liu
1

Mac OS X avec DarwinPorts:

sudo port install unsort
cat $file | unsort | ...
Coroos
la source
1

FreeBSD a son propre utilitaire aléatoire:

cat $file | random | ...

C'est dans / usr / games / random, donc si vous n'avez pas installé de jeux, vous n'avez pas de chance.

Vous pouvez envisager d'installer des ports tels que textproc / rand ou textproc / msort. Ceux-ci pourraient bien être disponibles sur Linux et / ou Mac OS X, si la portabilité est un problème.

Coroos
la source
-1

Sur Mac OS X, saisissant des dernières nouvelles de http://ftp.gnu.org/gnu/coreutils/ et quelque chose comme

./configure make sudo make install

... devrait vous donner / usr / local / bin / sort --random-sort

sans gâcher / usr / bin / sort

Dan Brickley
la source
cela n'a pas fonctionné pour moi sur OSX (10.7). J'ai "configure: erreur: le compilateur C ne peut pas créer d'exécutables".
Dolan Antenucci
@dolan Vérifiez vos autorisations?
Benubird
-1

Ou obtenez-le de MacPorts:

$ sudo port install coreutils

et / ou

$ /opt/local//libexec/gnubin/sort --random-sort
Chadwick Boggs
la source