Quel est un moyen facile de lire une ligne aléatoire à partir d'un fichier en ligne de commande Unix?
linux
unix
random
command-line
codeforester
la source
la source
Réponses:
Vous pouvez utiliser
shuf
:Il existe également un utilitaire appelé
rl
. Dans Debian, c'est dans lerandomize-lines
package qui fait exactement ce que vous voulez, bien qu'il ne soit pas disponible dans toutes les distributions. Sur sa page d'accueil, il recommande en fait l'utilisation deshuf
plutôt (qui n'existait pas lors de sa création, je crois).shuf
fait partie des coreutils GNU,rl
n'est pas.la source
shuf
conseil, il est intégré à Fedora.sort -R
va certainement faire attendre beaucoup s'il s'agit de fichiers considérablement volumineux - lignes de 80kk -, alors qu'ilshuf -n
agit assez instantanément.coreutils
depuis Homebrew. Peut être appelé à lagshuf
place deshuf
.randomize-lines
sur OS X parbrew install randomize-lines; rl -c 1 $FILE
shuf
fait partie de GNU Coreutils et ne sera donc pas nécessairement disponible (par défaut) sur les systèmes * BSD (ou Mac?). Le perl one-liner de @ Tracker1 ci-dessous est plus portable (et d'après mes tests, est légèrement plus rapide).Une autre alternative:
la source
(${RANDOM} << 15) + ${RANDOM}
. Cela réduit considérablement le biais et lui permet de fonctionner pour les fichiers contenant jusqu'à 1 milliard de lignes.+
et|
sont les mêmes depuis${RANDOM}
0..32767 par définition.(J'aime encore mieux l'approche shuf ci-dessus - je ne savais même pas qu'elle existait et je n'aurais jamais trouvé cet outil par moi-même)
la source
sort
, qui ne fonctionne sur aucun de mes systèmes (CentOS 5.5, Mac OS 10.7.2). En outre, l'utilisation inutile de chat pourrait être réduite àsort --random-sort < $FILE | head -n 1
sort -R <<< $'1\n1\n2' | head -1
est aussi susceptible de renvoyer 1 et 2, carsort -R
trie les lignes en double ensemble. La même chose s'applique àsort -Ru
, car elle supprime les lignes en double.sort
avant de le redirigerhead
.shuf
sélectionne plutôt des lignes aléatoires dans le fichier et est beaucoup plus rapide pour moi.sort --random-sort $FILE | head
serait mieux, car il lui permet d'accéder directement au fichier, ce qui permet peut-être un tri parallèle efficace--random-sort
et-R
sont spécifiques au tri GNU (elles ne fonctionneront donc pas avec BSD ou Mac OSsort
). Le tri GNU a appris ces indicateurs en 2005, vous avez donc besoin de GNU coreutils 6.0 ou plus récent (par exemple CentOS 6).C’est simple.
Certes, c'est juste un peu plus lent que le "shuf -n 1 file.txt" seul.
la source
-n 1
spécifie 1 ligne, et vous pouvez la changer en plus de 1.shuf
peut également être utilisée pour d'autres choses; Je viens de jouer avecps aux
etgrep
pour tuer au hasard des processus correspondant partiellement à un nom.perlfaq5: Comment sélectionner une ligne aléatoire dans un fichier? Voici un algorithme d'échantillonnage de réservoir du Camel Book:
Cela présente un avantage d'espace considérable par rapport à la lecture de l'intégralité du fichier. Vous pouvez trouver une preuve de cette méthode dans The Art of Computer Programming, Volume 2, Section 3.4.2, de Donald E. Knuth.
la source
shuf
. Le code Perl est très légèrement plus rapide (8% plus rapide par le temps de l'utilisateur, 24% plus rapide par le temps du système), bien que je trouve anecdotique que le code Perl "semble" moins aléatoire (j'ai écrit un juke-box en l'utilisant).shuf
stocke l'intégralité du fichier d'entrée en mémoire , ce qui est une idée horrible, tandis que ce code ne stocke qu'une seule ligne, donc la limite de ce code est un nombre de lignes de INT_MAX (2 ^ 31 ou 2 ^ 63 selon votre arc), en supposant que l'une de ses lignes potentielles sélectionnées tient en mémoire.en utilisant un script bash:
la source
Ligne de bash unique:
Petit problème: nom de fichier en double.
la source
wc -l < test.txt
évite d'avoir à canalisercut
.Voici un simple script Python qui fera le travail:
Usage:
la source
import random, sys lines = open(sys.argv[1]).readlines()
pour i dans la plage (len (lignes)): rand = random.randint (0, len (lignes) -1) print lines.pop (rand),len(lines)
peut donc conduire à IndexError. Vous pourriez utiliserprint(random.choice(list(open(sys.argv[1]))))
. Il existe également un algorithme d'échantillonnage de réservoir efficace en mémoire .Une autre façon d'utiliser ' awk '
la source
$RANDOM
est un bashisme ). Voici une méthode pure awk (mawk) utilisant la même logique que le code perlfaq5 cité par @ Tracker1 ci-dessus:awk 'rand() * NR < 1 { line = $0 } END { print line }' file.name
(wow, c'est encore plus court que le code perl!)wc
) afin d'obtenir un nombre de lignes, puis doit relire (une partie du) fichier (awk
) pour obtenir le contenu du numéro de ligne aléatoire donné. Les E / S coûteront beaucoup plus cher que d'obtenir un nombre aléatoire. Mon code lit le fichier une seule fois. Le problème avec awkrand()
est qu'il se base sur quelques secondes, vous obtiendrez donc des doublons si vous l'exécutez consécutivement trop rapidement.Une solution qui fonctionne également sur MacOSX, et devrait également fonctionner sur Linux (?):
Où:
N
est le nombre de lignes aléatoires que vous voulezNR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2
-> enregistrer les numéros de ligne écritsfile1
puis imprimer la ligne correspondantefile2
jot -r $N 1 $(wc -l < $file)
-> dessiner desN
nombres au hasard (-r
) dans la plage(1, number_of_line_in_file)
avecjot
. La substitution de processus<()
le fera ressembler à un fichier pour l'interpréteur, doncfile1
dans l'exemple précédent.la source
la source
Voici ce que je découvre puisque mon Mac OS n'utilise pas toutes les réponses faciles. J'ai utilisé la commande jot pour générer un nombre car les solutions de variables $ RANDOM ne semblent pas être très aléatoires dans mon test. Lors du test de ma solution, j'avais une grande variance dans les solutions fournies dans la sortie.
L'écho de la variable est d'obtenir un visuel du nombre aléatoire généré.
la source
En utilisant uniquement vanilla sed et awk, et sans utiliser $ RANDOM, un "one-liner" simple, peu encombrant et relativement rapide pour sélectionner une seule ligne de manière pseudo-aléatoire dans un fichier nommé FILENAME est le suivant:
(Cela fonctionne même si FILENAME est vide, auquel cas aucune ligne n'est émise.)
Un avantage possible de cette approche est qu'elle n'appelle rand () qu'une seule fois.
Comme l'a souligné @AdamKatz dans les commentaires, une autre possibilité serait d'appeler rand () pour chaque ligne:
(Une simple preuve d'exactitude peut être donnée sur la base de l'induction.)
Méfiez-vous de
rand()
"Dans la plupart des implémentations awk, y compris gawk, rand () commence à générer des nombres à partir du même numéro de départ, ou graine, chaque fois que vous exécutez awk."
- https://www.gnu.org/software/gawk/manual/html_node/Numeric-Functions.html
la source