¿Cómo puedo aleatorizar las líneas en un archivo usando herramientas estándar en Red Hat Linux?


102

¿Cómo puedo aleatorizar las líneas en un archivo usando herramientas estándar en Red Hat Linux?

No tengo el shufcomando, así que estoy buscando algo como una perlo awkuna línea que logre la misma tarea.


1
Hice casi la misma pregunta [ stackoverflow.com/questions/286640/…
Steve Schnepp


Considero a gcc como una herramienta estándar en cualquier linux. ; D
msb

Respuestas:


64

¡Y obtienes un one-liner de Perl!

perl -MList::Util -e 'print List::Util::shuffle <>'

Utiliza un módulo, pero el módulo es parte de la distribución del código Perl. Si eso no es lo suficientemente bueno, puede considerar lanzar el suyo.

Intenté usar esto con la -ibandera ("editar en el lugar") para que editara el archivo. La documentación sugiere que debería funcionar, pero no es así. Todavía muestra el archivo mezclado en stdout, pero esta vez elimina el original. Le sugiero que no lo use.

Considere un script de shell:

#!/bin/sh

if [[ $# -eq 0 ]]
then
  echo "Usage: $0 [file ...]"
  exit 1
fi

for i in "$@"
do
  perl -MList::Util -e 'print List::Util::shuffle <>' $i > $i.new
  if [[ `wc -c $i` -eq `wc -c $i.new` ]]
  then
    mv $i.new $i
  else
    echo "Error for file $i!"
  fi
done

No probado, pero con suerte funciona.


Para hacer una copia de seguridad del archivo original, puede agregar una extensión al indicador -i [ perldoc.perl.org/perlrun.html]
Steve Schnepp

Normalmente soy un fan de Perl, pero me encontré con este ejemplo de rubí, que tiene la ventaja de ser más corto: ruby -e 'puts STDIN.readlines.shuffle'. Sería necesario realizar pruebas en grandes entradas para ver si la velocidad es comparable. (también funciona en OS X)
mivk

según el comentario a continuación, shufcarga todo en la memoria, por lo que no funciona con un archivo realmente enorme (el mío es ~ 300GB tsv). Este script de Perl también falló en el mío, pero sin ningún error excepto Killed. ¿Alguna idea de si la solución de Perl también está cargando todo en la memoria, o hay algún otro problema que estoy encontrando?
seth127

211

Um, no olvidemos

sort --random-sort

1
Bueno, estoy usando gnu-coreutils 7.1 (instalación estándar de gentoo), que tiene ordenamiento con esta opción, no estoy seguro de cuándo apareció o si está en otras implementaciones.
Jim T

1
La función se comprometió el 10 de diciembre de 2005, el lanzamiento siguiente fue 5.94, así que supongo que ha estado disponible desde esa versión.
Jim T

41
En OS X puede instalar gnu coreutils con homebrew: brew install coreutilstodas las utilidades tienen el prefijo ag así: gsort --random-sorto gshuffuncionarán como se esperaba
mike

3
+1 @mike. Yo uso Macports y también tenía gsorte gshufinstalé cuando lo hiceport install coreutils
Noah Sussman

10
Esta solución solo es buena si sus líneas no tienen repeticiones. Si es así, todas las instancias de esa línea aparecerán una al lado de la otra. Considere usar en su shuflugar (en Linux).
Ali J

118

shuf Es la mejor manera.

sort -Res dolorosamente lento. Intenté ordenar el archivo de 5GB. Me di por vencido después de 2,5 horas. Luego lo shufordené en un minuto.


Esto es genial. Parece estar en GNU coreutils.
ariddell

4
Sospecho que la razón sort -Res lenta es que calcula un hash para cada línea. De los documentos: " Ordene por hash de las claves de entrada y luego clasifique los valores hash " .
Joe Flynn

13
cuidado, shufcarga todo en la memoria.
jfs

1
@benroth: Por lo que puedo decir, con recuentos de entrada realmente grandes, aumentar la memoria puede ayudar un poco , pero sigue siendo lento en general. En mis pruebas, la clasificación de un archivo de entrada de 1 millón de línea creada con la seq -f 'line %.0f' 1000000tomó el mismo, a largo tiempo de proceso (mucho, mucho más tiempo que con shuf), sin importar la cantidad de memoria Asigné.
mklement0

1
@ mklement0, ¡tienes razón! Lo intenté con un archivo mucho más grande que el que tenía antes, y el hash parece ser el cuello de botella.
benroth

23
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Lea el archivo, anteponga cada línea con un número aleatorio, ordene el archivo por esos prefijos aleatorios, luego corte los prefijos. Una línea que debería funcionar en cualquier caparazón semi-moderno.

EDITAR: incorporó los comentarios de Richard Hansen.


1
Esto funciona y es una solución creativa, pero eliminará los espacios en blanco iniciales en las líneas.
Chris Lutz

@Chris cambiando el último corte a | sed 's / ^ [^ \ t] * \ t //' debería arreglar eso
bdonlan

Felicitaciones a la simplicidad del enfoque.
Shashikant Kore

3
+1 para la conformidad con POSIX (excepto $RANDOM), pero -1 para eliminar los datos. Reemplazar while read fcon while IFS= read -r fevitará readque se eliminen los espacios en blanco iniciales y finales (consulte esta respuesta ) y evitará el procesamiento de barras invertidas. El uso de una cadena aleatoria de longitud fija evitará que se cuteliminen los espacios en blanco iniciales. Resultado: cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-
Richard Hansen

3
@Richard Hansen: Gracias, estos cambios sugeridos son obviamente apropiados, he editado mi publicación.
ChristopheD

9

Una sola línea para Python:

python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile

Y para imprimir una sola línea aleatoria:

python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile

Pero vea esta publicación para conocer los inconvenientes de python random.shuffle(). No funcionará bien con muchos elementos (más de 2080).


5

Relacionado con la respuesta de Jim:

Mi ~/.bashrccontiene lo siguiente:

unsort ()
{
    LC_ALL=C sort -R "$@"
}

Con sort, -R= de GNU coreutils --random-sort, que genera un hash aleatorio de cada línea y las ordena. El hash aleatorio en realidad no se usaría en algunas configuraciones regionales en algunas versiones más antiguas (con errores), lo que hace que devuelva una salida ordenada normal, por lo que configuré LC_ALL=C.


Relacionado con la respuesta de Chris:

perl -MList::Util=shuffle -e'print shuffle<>'

es un delineador ligeramente más corto. ( -Mmodule=a,b,ces la abreviatura de -e 'use module qw(a b c);'.)

La razón por la que darle un simple -ino funciona para barajar en el lugar es porque Perl espera que printsuceda en el mismo bucle en el que se está leyendo el archivo, y print shuffle <>no genera salida hasta que todos los archivos de entrada se han leído y cerrado.

Como solución temporal más breve,

perl -MList::Util=shuffle -i -ne'BEGIN{undef$/}print shuffle split/^/m'

mezclará los archivos en su lugar. ( -nsignifica "envolver el código en un while (<>) {...}bucle; BEGIN{undef$/}hace que Perl opere en archivos a la vez en lugar de líneas a la vez, y split/^/mes necesario porque $_=<>se ha hecho implícitamente con un archivo completo en lugar de líneas).


Reiterando ese tipo -R no existe en OS X, pero +1 para algunas excelentes respuestas de Perl, y una excelente respuesta en general.
Chris Lutz

Podrías instalar GNU coreutils en OS X, pero (como he hecho en el pasado) debes tener cuidado de no romper las herramientas integradas ... Dicho esto, OP está en Redhat Linux, que definitivamente tiene GNU estándar de coreutils.
ephemient

3

Cuando instalo coreutils con homebrew

brew install coreutils

shufestá disponible como n.


brew prefijo todos los comandos con glo que se shufconvirtió gshufpara mí.
Jörn

^ ¿Es eso porque no son POSIX, o estoy totalmente fuera de lugar?
Dave Liu

1

Mac OS X con DarwinPorts:

sudo port install unsort
cat $file | unsort | ...

1

FreeBSD tiene su propia utilidad aleatoria:

cat $file | random | ...

Está en / usr / games / random, así que si no ha instalado juegos, no tiene suerte.

Podría considerar instalar puertos como textproc / rand o textproc / msort. Estos pueden estar disponibles en Linux y / o Mac OS X, si la portabilidad es una preocupación.


-1

En OSX, obteniendo lo último de http://ftp.gnu.org/gnu/coreutils/ y algo como

./configure make sudo make install

... debería darle / usr / local / bin / sort --random-sort

sin estropear / usr / bin / sort


esto no funcionó para mí en OSX (10.7). Obtuve "configure: error: el compilador de C no puede crear ejecutables".
Dolan Antenucci

@dolan ¿Verifica sus permisos?
Benubird

-1

O consígalo en MacPorts:

$ sudo port install coreutils

y / o

$ /opt/local//libexec/gnubin/sort --random-sort
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.