Comment puis-je mélanger les lignes d'un fichier texte sur la ligne de commande Unix ou dans un script shell?
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 .]
Perl one-liner serait une version simple de la solution de Maxim
perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
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 sortie141
), 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
, etcut
, adapté de la OP's own answer :
shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), " 151900920"}' "$@" |
sort -k1,1n | cut -d ' ' -f2-; }
- Perl - fonction basée-adapté de réponse de Moonyoung Kang :
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
- Python - fonction basée, adapté de réponse de scai :
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))
' "$@"; }
- Ruby - fonction basée, adapté de réponse de hoffmanc :
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 BSDawk
;2.388s
avec GNUawk
(4.1.1);1.811s
avecmawk
(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 ; quiawk
implémentation que vous utilisez matters (mawk
est plus rapide que GNUawk
, BSDawk
est plus lent). - Rester à l'écart de
sort -R
,bash
les boucles et la Scala.
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'.
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
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
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).
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).
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
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'
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
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
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
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)'
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
}
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.
pas encore mentionné:
-
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 ...]
-
seq 10 | msort -jq -b -l -n 1 -c r
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];
}
}