Tengo una lista de datos, como
12345
23456
67891
-20000
200
600
20
...
Suponga que el tamaño de este conjunto de datos (es decir, líneas de archivo) es N
. Quiero dibujar m
líneas al azar de este archivo de datos. Por lo tanto, el resultado debe ser dos archivos, uno es el archivo que incluye estas m
líneas de datos y el otro incluye N-m
líneas de datos.
¿Hay alguna manera de hacerlo usando un comando de Linux?
linux
shell
text-processing
usuario288609
fuente
fuente
Respuestas:
Puede que esta no sea la forma más eficiente, pero funciona:
Con que
$m
contiene el número de líneas.fuente
sort -R
se encarga de la aleatoriedad. No estoy seguro si rechazó la respuesta para eso, pero primero búsquela en la página de manual.sort -R
no ordena exactamente su entrada al azar: agrupa líneas idénticas. Así que si la entrada es, por ejemplofoo
,foo
,bar
,bar
y m = 2, entonces un archivo contendrá ambosfoo
s y el otro contendrá ambosbar
s. GNU coreutils también tieneshuf
, que aleatoriza las líneas de entrada. Además, no necesita un archivo temporal .shuf <file> |head -n $m
?Este script bash / awk elige líneas al azar y mantiene la secuencia original en ambos archivos de salida.
Salida, basada en los datos de la pregunta.
fuente
Como con todas las cosas de Unix, hay una utilidad para esa TM .
Programa del día:
split
split
dividirá un archivo de muchas maneras diferentes,-b
bytes,-l
líneas,-n
número de archivos de salida. Usaremos la-l
opción. Como desea elegir líneas aleatorias y no solo la primeram
, primerosort
archivaremos al azar. Si desea leer sobresort
, consulte mi respuesta aquí .Ahora, el código real. Es bastante simple, realmente:
Esto creará dos archivos, uno con
m
líneas y otro conN-m
líneas, llamadosoutput_prefixaa
youtput_prefixab
. Asegúrese de quem
sea el archivo más grande que desea o obtendrá varios archivos de longitudm
(y uno conN % m
).Si desea asegurarse de usar el tamaño correcto, aquí hay un pequeño código para hacerlo:
Editar: Me ha llamado la atención que algunas
sort
implementaciones no tienen una-R
bandera. Si es asíperl
, puede sustituirloperl -e 'use List::Util qw/shuffle/; print shuffle <>;'
.fuente
sort -R
parece estar solo en algunas versiones de tipo (probablemente la versión gnu). Para otras plataformas escribí una herramienta llamada 'randline' que no hace más que aleatorizar stdin. Está en beesbuzz.biz/code para cualquiera que lo necesite. (Tiendo a barajar bastante el contenido de los archivos)sort -R
no ordena exactamente su entrada al azar: agrupa líneas idénticas. Así que si la entrada es, por ejemplofoo
,foo
,bar
,bar
y m = 2, entonces un archivo contendrá ambosfoo
s y el otro contendrá ambosbar
s. GNU coreutils también tieneshuf
, que aleatoriza las líneas de entrada. Además, puede elegir los nombres de los archivos de salida utilizandohead
y entail
lugar desplit
.Si no le importa reordenar las líneas y tiene coreutils de GNU (es decir, en Linux o Cygwin no integrados, no demasiado antiguos desde que
shuf
apareció en la versión 6.0),shuf
("barajar") reordena las líneas de un archivo al azar. Por lo tanto, puede mezclar el archivo y enviar las primeras m líneas a un archivo y el resto a otro.No hay una forma ideal de hacer ese despacho. No puedes simplemente encadenar
head
ytail
porquehead
se amortiguaría. Puede usarsplit
, pero no obtiene ninguna flexibilidad con respecto a los nombres de los archivos de salida. Puedes usarawk
, por supuesto:Puede usarlo
sed
, que es oscuro pero posiblemente más rápido para archivos grandes.O puede usar
tee
para duplicar los datos, si su plataforma lo ha hecho/dev/fd
; está bien si m es pequeño:Portablemente, puede usar awk para despachar cada línea por turno. Tenga en cuenta que awk no es muy bueno para inicializar su generador de números aleatorios; la aleatoriedad no solo definitivamente no es adecuada para la criptografía, sino que ni siquiera es muy buena para las simulaciones numéricas. La semilla será la misma para todas las invocaciones awk en cualquier sistema dentro de un período de un segundo.
Si necesita una mejor aleatoriedad, puede hacer lo mismo en Perl, que siembra decentemente su RNG.
fuente
awk
ejemplo:-v N=$(wc -l <file) -v m=4
... y solo imprime una línea "aleatoria" cuando el valor aleatorio es menor que$m
, en lugar de imprimir$m
líneas aleatorias ... Parece queperl
puede estar haciendo lo mismo con rand , pero no no sé loperl
suficiente como para superar un error de compilación: error de sintaxis en la línea 7, cerca de ") print"shuf
ejemplo.head
cat
combo causa la pérdida de datos en la segunda prueba siguiente 3-4 ... PRUEBA 1-2{ for i in {00001..10000} ;do echo $i; done; } | { head -n 5000 >out1; cat >out2; }
... PRUEBA 3-4{ for i in {00001..10000} ;do echo $i; done; } >input; cat input | { head -n 5000 >out3; cat >out4; }
... loswc -l
resultados para las salidas de PRUEBA 1-2 son 5000 5000 (bueno), pero para PRUEBA 3-4 son 5000 4539 (no es bueno). La diferencia varía según los tamaños de archivo involucrados ... Aquí hay un enlace a mi código de pruebahead
lee por delante; lo que lee más adelante y no se imprime se descarta. He actualizado mi respuesta con soluciones menos elegantes pero correctas (estoy razonablemente seguro).Asumiendo
m = 7
yN = 21
:Nota: Si reemplaza
7
con una variable como$1
o$m
, debe usarseq
, no la{from..to}
notación, que no hace expansión de variable.Funciona eliminando línea por línea del archivo, que se acorta cada vez más, por lo que el número de línea, que se puede eliminar, debe hacerse cada vez más pequeño.
Esto no debe usarse para archivos más largos y para muchas líneas, ya que para cada número, en promedio, el medio archivo debe leerse para el primero y el archivo completo para el segundo código sed .
fuente
including them
pero también las líneas originales, por lo tantoincluding
, noconsisting of
, y no usaronly
, pero supongo que su interpretación es lo que el usuario 288609 quería decir. Ajustaré mi script en consecuencia.+1
en el lugar equivocado. Debería serrnd=$((RANDOM%(N-i)+1))
donde N = 21 en su ejemplo. Actualmente hacesed
que se bloquee cuandornd
se evalúa0
. .. Además, no se escala muy bien con toda esa reescritura de archivos. por ejemplo, 123 segundos para extraer 5.000 líneas al azar a partir de un archivo de 10.000 línea frente a 0,03 segundos de un método más directo ...