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.
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.
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.
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.
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. "
Un fichier de 1,7GB et 28 millions de lignes sur Linux Debian Wheezy a été randomisé en quelques minutes, acceptable
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.
Pour sauvegarder le fichier original, vous pouvez ajouter une extension à l'option -i [ [perldoc.perl.org/perlrun.html]](http://perldoc.perl.org/perlrun.html])
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)
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 ?
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.
Cela fonctionne, et c'est une solution créative, mais cela supprimera les espaces blancs sur les lignes.
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).
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.
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.
1 votes
J'ai posé presque la même question [ stackoverflow.com/questions/286640/
0 votes
Duplicata possible de Comment mélanger les lignes d'un fichier texte en ligne de commande Unix ?
0 votes
Je considère gcc comme un outil standard dans tout linux ;D