¿Cuál es una manera fácil de leer una línea aleatoria de un archivo en la línea de comandos de Unix?

¿Cuál es una manera fácil de leer una línea aleatoria de un archivo en la línea de comandos de Unix?

Puedes usar shuf :

 shuf -n 1 $FILE 

También hay una utilidad llamada rl . En Debian está en el paquete de randomize-lines que hace exactamente lo que usted desea, aunque no está disponible en todas las distribuciones. En su página de inicio, en realidad recomienda el uso de shuf lugar (que no existía cuando se creó, creo). shuf es parte de los coreutils de GNU, rl no lo es.

 rl -c 1 $FILE 

Otra alternativa:

 head -$((${RANDOM} % `wc -l < file` + 1)) file | tail -1 
 sort --random-sort $FILE | head -n 1 

(Aunque me gusta el enfoque shuf incluso mejor; ni siquiera sabía que existía y nunca habría encontrado esa herramienta por mi cuenta)

Esto es simple.

 cat file.txt | shuf -n 1 

De acuerdo, esto es solo un poco más lento que el “shuf -n 1 file.txt” por sí mismo.

perlfaq5: ¿cómo selecciono una línea aleatoria de un archivo? Aquí hay un algoritmo de muestreo de yacimientos del Camel Book:

 $ perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' file 

Esto tiene una ventaja significativa en el espacio sobre la lectura de todo el archivo. Puede encontrar una prueba de este método en The Art of Computer Programming, Volumen 2, Sección 3.4.2, de Donald E. Knuth.

usando 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} 

Línea de bash individual:

 sed -n $((1+$RANDOM%`wc -l test.txt | cut -f 1 -d ' '`))p test.txt 

Ligero problema: nombre de archivo duplicado.

Aquí hay un script simple de Python que hará el trabajo:

 import random, sys lines = open(sys.argv[1]).readlines() print(lines[random.randrange(len(lines))]) 

Uso:

 python randline.py file_to_get_random_line_from 

Otra forma de usar ‘ awk

 awk NR==$((${RANDOM} % `wc -l < file.name` + 1)) file.name 

Una solución que también funciona en MacOSX, y también debería funcionar en Linux (?):

 N=5 awk 'NR==FNR {lineN[$1]; next}(FNR in lineN)' < (jot -r $N 1 $(wc -l < $file)) $file 

Dónde:

  • N es la cantidad de líneas aleatorias que deseas

  • NR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2 NR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2 -> guarde los números de línea escritos en el file1 y luego imprima la línea correspondiente en el file2

  • jot -r $N 1 $(wc -l < $file) -> dibuja N números aleatoriamente ( -r ) en el rango (1, number_of_line_in_file) con jot . La sustitución del proceso < () hará que parezca un archivo para el intérprete, por lo que el archivo file1 en el ejemplo anterior.
 #!/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]} 

Esto es lo que descubrí porque mi Mac OS no usa todas las respuestas fáciles. Usé el comando jot para generar un número ya que las soluciones con la variable $ RANDOM no parecen ser muy aleatorias en mi prueba. Al probar mi solución tuve una amplia variación en las soluciones proporcionadas en la salida.

  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 

El eco de la variable es obtener una vista del número aleatorio generado.

Usando solo vanilla sed y awk, y sin usar $ RANDOM, un simple “one-liner” eficiente en el uso del espacio y razonablemente rápido para seleccionar una sola línea pseudoaleatoriamente de un archivo llamado FILENAME es el siguiente:

 sed -n $(awk 'END {srand(); r=rand()*NR; if (r 

(Esto funciona incluso si FILENAME está vacío, en cuyo caso no se emite ninguna línea).

Una posible ventaja de este enfoque es que solo llama a rand () una vez.

Como señaló @AdamKatz en los comentarios, otra posibilidad sería llamar a rand () para cada línea:

 awk 'rand() * NR < 1 { line = $0 } END { print line }' FILENAME 

(Se puede dar una prueba simple de corrección basada en la inducción).

Advertencia sobre rand()

"En la mayoría de las implementaciones de awk, incluido gawk, rand () comienza a generar números a partir del mismo número inicial, o semilla, cada vez que ejecuta awk".

- https://www.gnu.org/software/gawk/manual/html_node/Numeric-Functions.html