344 votes

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

Je veux mélanger les lignes d'un fichier texte de façon aléatoire et créer un nouveau fichier. Le fichier peut contenir plusieurs milliers de lignes.

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

4 votes

0 votes

Oui, il y a aussi d'autres bonnes réponses à cette question originale.

0 votes

Alors, tu faisais une liste de mots pour le WPA ? (juste une supposition aléatoire)

422voto

Joey Points 148544

Vous pouvez utiliser shuf . Sur certains systèmes au moins (cela ne semble pas être dans POSIX).

Comme jleedev l'a souligné : sort -R pourrait également être une option. Sur certains systèmes du moins ; enfin, vous voyez le tableau. Il a été souligné que sort -R ne mélange pas vraiment les éléments mais les trie en fonction de leur valeur de hachage.

[Note de l'éditeur : sort -R casi mélange, sauf que dupliquer les lignes / clés de tri finissent toujours par à côté l'un de l'autre . En d'autres termes : seulement avec unique lignes d'entrée / touches, c'est un vrai shuffle. Même s'il est vrai que l'ordre de sortie est déterminé par valeurs de hachage le caractère aléatoire provient du choix d'un hash aléatoire. fonction - voir manuel .]

0 votes

Cool, je ne connaissais pas le shuf. Il semble qu'il fasse partie de coreutils mais la version que j'ai installée sur mon serveur n'a pas shuf.

0 votes

Ouais, il semble que ce soit des trucs réservés aux GNU, malheureusement. Rien de tout cela dans POSIX.

2 votes

C'est étrange que GNU coreutils ait à la fois shuf y sort -R .

93voto

Moonyoung Kang Points 281

Un langage Perl unique serait une version simple de la solution de Maxim.

perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile

7 votes

Je l'ai aliasé en shuffle sur OS X. Merci !

0 votes

C'était le seul script de cette page qui retournait de VRAIES lignes aléatoires. Les autres solutions awk imprimaient souvent des sorties en double.

1 votes

Mais attention, car à la sortie, vous perdrez une ligne :) Elle sera simplement jointe à une autre ligne :)

26voto

NickZoic Points 2406

J'utilise un minuscule script en perl, que j'appelle "unsort" :

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

J'ai aussi une version délimitée par NULL, appelée "unsort0" ... pratique à utiliser avec find -print0 et ainsi de suite.

PS : J'ai voté pour 'shuf' aussi, je n'avais aucune idée que cela existait dans coreutils ces jours-ci ... ce qui précède peut toujours être utile si votre système n'a pas 'shuf'.

0 votes

Joli, RHEL 5.6 n'a pas de shuf (

1 votes

Bien fait ; je suggère de remplacer <STDIN> con <> afin de faire fonctionner la solution avec des entrées provenant de fichiers aussi.

24voto

Amaç Herdağdelen Points 2452

Voici un premier essai, facile pour le codeur mais difficile pour le processeur, qui ajoute un nombre aléatoire à chaque ligne, les trie et retire ensuite le nombre aléatoire de chaque ligne. En fait, les lignes sont triées de façon aléatoire :

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

9 votes

UUOC. passe le fichier à l'awk lui-même.

1 votes

Bon, je débogue avec head myfile | awk ... . Ensuite, je le change en chat ; c'est pourquoi il a été laissé là.

0 votes

Pas besoin -k1 -n pour le tri, puisque la sortie de l'awk rand() est une décimale entre 0 et 1 et parce que tout ce qui compte est qu'elle soit réorganisée d'une manière ou d'une autre. -k1 pourrait aider à accélérer le processus en ignorant le reste de la ligne, bien que la sortie de rand() devrait être suffisamment unique pour court-circuiter la comparaison.

16voto

ghostdog74 Points 86060

Voici un script awk

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

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

0 votes

Bien fait, mais dans la pratique beaucoup plus lent que la réponse du PO lui-même qui combine awk con sort y cut . Pour un nombre de lignes inférieur à quelques milliers, cela ne fait pas une grande différence, mais pour un nombre de lignes plus élevé, cela a de l'importance (le seuil dépend de la taille de la ligne). awk utilisée). Une légère simplification consisterait à remplacer les lignes while (1){ y if (e==d) {break} con while (e<d) .

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