Quel est un moyen facile de lire une ligne aléatoire à partir d'un fichier en ligne de commande Unix?
Vous pouvez utiliser shuf
:
shuf -n 1 $FILE
Il existe également un utilitaire appelé rl
. Dans Debian, c’est le paquet randomize-lines
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 d’utiliser shuf
(ce qui n’existait pas au moment de sa création, je crois). shuf
fait partie de GNU coreutils, rl
ne l’est pas.
rl -c 1 $FILE
Une autre alternative:
head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1
sort --random-sort $FILE | head -n 1
(J'aime encore mieux l'approche shuf ci-dessus - je ne savais même pas que cela existait et je n'aurais jamais trouvé cet outil seul)
C'est simple.
cat file.txt | shuf -n 1
Ceci est un peu moins rapide que "shuf -n 1 fichier.txt".
perlfaq5: Comment sélectionner une ligne au hasard dans un fichier? Voici un algorithme d'échantillonnage de réservoir du Camel Book:
$ Perl -e 'srand; Rand($.) < 1 && ($line = $_) while <>; print $line;' file
Ceci présente un avantage significatif en termes d'espace par rapport à la lecture de l'ensemble 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.
en utilisant un script bash:
#!/bin/bash
# replace with file to read
FILE=tmp.txt
# count number of lines
NUM=$(wc - l < ${FILE})
# generate random number in range 0-NUM
let X=${RANDOM} % ${NUM} + 1
# extract X-th line
sed -n ${X}p ${FILE}
Ligne bash unique:
sed -n $((1+$RANDOM%`wc -l test.txt | cut -f 1 -d ' '`))p test.txt
Petit problème: nom de fichier en double.
Voici un script Python simple qui fera le travail:
import random, sys
lines = open(sys.argv[1]).readlines()
print(lines[random.randrange(len(lines))])
Usage:
python randline.py file_to_get_random_line_from
Une autre façon en utilisant ' awk '
awk NR==$((${RANDOM} % `wc -l < file.name` + 1)) file.name
Une solution qui fonctionne aussi sur MacOSX, et devrait aussi fonctionner sur Linux (?):
N=5
awk 'NR==FNR {lineN[$1]; next}(FNR in lineN)' <(jot -r $N 1 $(wc -l < $file)) $file
Où:
N
est le nombre de lignes aléatoires que vous voulez
NR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2
--> enregistrez les numéros de ligne écrits en file1
puis imprimez la ligne correspondante en file2
jot -r $N 1 $(wc -l < $file)
-> draw N
nombres aléatoirement (-r
) dans la plage (1, number_of_line_in_file)
avec jot
. Le processus de substitution <()
le fera ressembler à un fichier pour l'interpréteur, donc file1
dans l'exemple précédent.En n'utilisant que Vanilla sed et awk, et sans utiliser $ RANDOM, vous trouverez ci-dessous une "ligne unique" simple, peu encombrante et assez rapide pour sélectionner une seule ligne pseudo-aléatoire à partir d'un fichier nommé FILENAME:
sed -n $(awk 'END {srand(); r=Rand()*NR; if (r<NR) {sub(/\..*/,"",r); r++;}; print r}' FILENAME)p FILENAME
(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 qu'une fois Rand ().
Comme l'a souligné @AdamKatz dans les commentaires, une autre possibilité serait d'appeler Rand () pour chaque ligne:
awk 'Rand() * NR < 1 { line = $0 } END { print line }' FILENAME
(Une simple preuve d'exactitude peut être donnée sur la base de l'induction.)
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
Voici ce que je découvre car mon Mac OS n’utilise pas toutes les réponses faciles. J'ai utilisé la commande jot pour générer un nombre car la solution de variable $ RANDOM ne semble pas être très aléatoire dans mon test. Lors du test de ma solution, les solutions fournies dans la sortie étaient très différentes.
RANDOM1=`jot -r 1 1 235886`
#range of jot ( 1 235886 ) found from earlier wc -w /usr/share/dict/web2
echo $RANDOM1
head -n $RANDOM1 /usr/share/dict/web2 | tail -n 1
L'écho de la variable est d'obtenir un visuel du nombre aléatoire généré.
#!/bin/bash
IFS=$'\n' wordsArray=($(<$1))
numWords=${#wordsArray[@]}
sizeOfNumWords=${#numWords}
while [ True ]
do
for ((i=0; i<$sizeOfNumWords; i++))
do
let ranNumArray[$i]=$(( ( $RANDOM % 10 ) + 1 ))-1
ranNumStr="$ranNumStr${ranNumArray[$i]}"
done
if [ $ranNumStr -le $numWords ]
then
break
fi
ranNumStr=""
done
noLeadZeroStr=$((10#$ranNumStr))
echo ${wordsArray[$noLeadZeroStr]}