106 votes

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

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

Je n'ai pas le shuf donc je cherche quelque chose comme une perl o awk qui accomplit la même tâche.

1 votes

J'ai posé presque la même question [ stackoverflow.com/questions/286640/

0 votes

0 votes

Je considère gcc comme un outil standard dans tout linux ;D

218voto

Jim T Points 7998

Um, n'oublions pas

sort --random-sort

0 votes

Pourriez-vous me dire quelle version de sort a cette option ?

1 votes

Eh bien, j'utilise gnu-coreutils 7.1 (installation standard de gentoo), qui a trié cette option, je ne sais pas quand elle est apparue, ou si elle est dans d'autres implémentations.

1 votes

La fonctionnalité a été ajoutée le 10 décembre 2005, la version suivante était la 5.94, donc je suppose qu'elle est disponible depuis cette version.

123voto

Michal Illich Points 520

shuf est le meilleur moyen.

sort -R est douloureusement lent. Je viens d'essayer de trier un fichier de 5 Go. J'ai abandonné après 2,5 heures. Puis shuf l'a réglé en une minute.

0 votes

C'est génial. Il semble que ce soit dans GNU coreutils.

4 votes

Je soupçonne que la raison sort -R est lent est qu'il calcule un hash pour chaque ligne. Dans la documentation : " Trier en hachant les clés d'entrée, puis en triant les valeurs de hachage. "

0 votes

Un fichier de 1,7GB et 28 millions de lignes sur Linux Debian Wheezy a été randomisé en quelques minutes, acceptable

64voto

Chris Lutz Points 34157

Et vous obtenez un one-liner en Perl !

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

Il utilise un module, mais ce module fait partie de la distribution du code Perl. Si cela ne suffit pas, vous pouvez envisager de développer votre propre module.

J'ai essayé de l'utiliser avec le -i ("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é sur stdout, mais cette fois il supprime l'original. Je vous suggère de ne pas l'utiliser.

Considérons un shell script :

#!/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 espérons qu'il fonctionne.

0 votes

Pour sauvegarder le fichier original, vous pouvez ajouter une extension à l'option -i [ [perldoc.perl.org/perlrun.html]](http://perldoc.perl.org/perlrun.html])

0 votes

Je suis habituellement un fan de Perl, mais je suis tombé sur cet exemple en ruby qui a l'avantage d'être plus court : ruby -e 'puts STDIN.readlines.shuffle' . Il faudrait le tester sur de grosses entrées pour voir si la vitesse est comparable. (fonctionne aussi sur OS X)

0 votes

Par commentaire ci-dessous, shuf charge tout en mémoire, donc il ne fonctionne pas avec un fichier vraiment énorme (le mien est un tsv de ~300GB). Ce script perl a échoué sur le mien aussi, mais sans erreur sauf Killed . Savez-vous si la solution perl charge également tout en mémoire, ou si je rencontre un autre problème ?

24voto

ChristopheD Points 38217
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Lire le fichier, faire précéder chaque ligne d'un numéro aléatoire, trier le fichier sur ces préfixes aléatoires, couper les préfixes ensuite. Une seule ligne qui devrait fonctionner dans n'importe quel shell semi-moderne.

EDIT : incorporé les remarques de Richard Hansen.

1 votes

Cela fonctionne, et c'est une solution créative, mais cela supprimera les espaces blancs sur les lignes.

0 votes

@Chris qui a changé la dernière coupe en "s/^[^]". \t ]* \t //' devrait régler ce problème

0 votes

Bravo pour la simplicité de l'approche !

5voto

ephemient Points 87003

En rapport avec la réponse de Jim :

Mon ~/.bashrc contient les éléments suivants :

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

Avec le sort de GNU coreutils, -R = --random-sort qui génère un hachage aléatoire de chaque ligne et le trie. Le hachage aléatoire n'est pas utilisé dans certaines locales dans certaines versions plus anciennes (boguées), ce qui fait qu'il retourne une sortie triée normale, c'est pourquoi j'ai mis LC_ALL=C .


En rapport avec la réponse de Chris :

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

est un texte un peu plus court. ( -Mmodule=a,b,c est un raccourci pour -e 'use module qw(a b c);' .)

La raison pour laquelle il s'agit d'une simple -i ne fonctionne pas pour le shuffling in-place parce que Perl s'attend à ce que le fichier print se produit dans la même boucle que la lecture du fichier, et print shuffle <> ne sort pas avant que tous les fichiers d'entrée aient été lus et fermés.

Comme solution de rechange plus courte,

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

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

0 votes

Je répète que sort -R n'existe pas sous OS X, mais +1 pour d'excellentes réponses en Perl, et une excellente réponse en général.

0 votes

Vous pourriez 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... Ceci étant dit, OP est sur Redhat Linux, qui a définitivement GNU coreutils en standard.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X