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 mlíneas al azar de este archivo de datos. Por lo tanto, el resultado debe ser dos archivos, uno es el archivo que incluye estas mlíneas de datos y el otro incluye N-mlí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
$mcontiene el número de líneas.fuente
sort -Rse encarga de la aleatoriedad. No estoy seguro si rechazó la respuesta para eso, pero primero búsquela en la página de manual.sort -Rno ordena exactamente su entrada al azar: agrupa líneas idénticas. Así que si la entrada es, por ejemplofoo,foo,bar,bary m = 2, entonces un archivo contendrá ambosfoos y el otro contendrá ambosbars. 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:
splitsplitdividirá un archivo de muchas maneras diferentes,-bbytes,-llíneas,-nnúmero de archivos de salida. Usaremos la-lopción. Como desea elegir líneas aleatorias y no solo la primeram, primerosortarchivaremos 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
mlíneas y otro conN-mlíneas, llamadosoutput_prefixaayoutput_prefixab. Asegúrese de quemsea 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
sortimplementaciones no tienen una-Rbandera. Si es asíperl, puede sustituirloperl -e 'use List::Util qw/shuffle/; print shuffle <>;'.fuente
sort -Rparece 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 -Rno ordena exactamente su entrada al azar: agrupa líneas idénticas. Así que si la entrada es, por ejemplofoo,foo,bar,bary m = 2, entonces un archivo contendrá ambosfoos y el otro contendrá ambosbars. GNU coreutils también tieneshuf, que aleatoriza las líneas de entrada. Además, puede elegir los nombres de los archivos de salida utilizandoheady entaillugar 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
shufapareció 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
headytailporqueheadse 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
teepara 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
awkejemplo:-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$mlíneas aleatorias ... Parece queperlpuede estar haciendo lo mismo con rand , pero no no sé loperlsuficiente como para superar un error de compilación: error de sintaxis en la línea 7, cerca de ") print"shufejemplo.headcatcombo 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 -lresultados 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 pruebaheadlee 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 = 7yN = 21:Nota: Si reemplaza
7con una variable como$1o$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 thempero 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.+1en el lugar equivocado. Debería serrnd=$((RANDOM%(N-i)+1))donde N = 21 en su ejemplo. Actualmente hacesedque se bloquee cuandorndse 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 ...