Come posso randomizzare le righe in un file utilizzando strumenti standard su Red Hat Linux?


102

Come posso randomizzare le righe in un file utilizzando strumenti standard su Red Hat Linux?

Non ho il shufcomando, quindi sto cercando qualcosa come una riga perlo awkuna riga che svolga lo stesso compito.


1
Ho posto quasi la stessa domanda [ stackoverflow.com/questions/286640/…
Steve Schnepp,


Considero gcc uno strumento standard in qualsiasi Linux. ; D
msb

Risposte:


64

E ottieni una battuta in Perl!

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

Usa un modulo, ma il modulo fa parte della distribuzione del codice Perl. Se questo non è abbastanza buono, potresti prendere in considerazione l'idea di rotolare il tuo.

Ho provato a usarlo con il -iflag ("edit-in-place") per farlo modificare il file. La documentazione suggerisce che dovrebbe funzionare, ma non è così. Visualizza ancora il file mescolato allo stdout, ma questa volta elimina l'originale. Ti suggerisco di non usarlo.

Considera uno script di 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

Non testato, ma si spera che funzioni.


Per eseguire il backup del file originale, puoi aggiungere un'estensione al flag -i [ perldoc.perl.org/perlrun.html]
Steve Schnepp,

Sono di solito un fan Perl, ma sono imbattuto in questo esempio ruby, che ha il vantaggio di essere più breve: ruby -e 'puts STDIN.readlines.shuffle'. Avrebbe bisogno di test su grandi input per vedere se la velocità è comparabile. (funziona anche su OS X)
mivk

per commento qui sotto, shufcarica tutto in memoria, quindi non funziona con un file veramente enorme (il mio è ~ 300 GB tsv). Anche questo script perl è fallito sul mio, ma senza errori tranne Killed. Qualche idea se la soluzione perl sta caricando tutto anche in memoria, o c'è qualche altro problema che sto riscontrando?
seth127

211

Um, non dimentichiamolo

sort --random-sort

1
Bene, sto usando gnu-coreutils 7.1 (installazione standard di gentoo), che ha sort con questa opzione, non sono sicuro di quando è apparso o se è in altre implementazioni.
Jim T

1
La funzione è stata attivata il 10 dicembre 2005, la versione successiva era la 5.94, quindi immagino che sia stata disponibile da quella versione.
Jim T

41
Su OS X puoi installare gnu coreutils con homebrew: brew install coreutilstutte le utilità hanno il prefisso ag quindi: gsort --random-sorto gshuffunzionerà come previsto
mike

3
+1 @mike. Uso Macports e ho anche avuto gsorte gshufinstallato quando l'ho fattoport install coreutils
Noah Sussman

10
Questa soluzione è valida solo se le tue linee non hanno ripetizioni. In tal caso, tutte le istanze di quella riga appariranno una accanto all'altra. Considera di usare shufinvece (su Linux).
Ali J

118

shuf è il modo migliore.

sort -Rè dolorosamente lento. Ho appena provato a ordinare il file da 5 GB. Ho rinunciato dopo 2,5 ore. Quindi shufrisolto in un minuto.


Questo è fantastico. Sembra essere in GNU coreutils.
ariddell

4
Sospetto che il motivo sort -Rsia lento è che calcola un hash per ogni riga. Dai documenti: " Ordina per hash delle chiavi di input e poi ordina i valori hash. "
Joe Flynn

13
attenzione, shufcarica tutto in memoria.
jfs

1
@benroth: Da quello che posso dire, con conteggi di input davvero grandi aumentare la memoria può aiutare in qualche modo , ma nel complesso è ancora lento. Nei miei test, l'ordinamento di un file di input da 1 milione di righe creato con seq -f 'line %.0f' 1000000ha richiesto lo stesso, molto tempo per l'elaborazione (molto, molto più a lungo rispetto a shuf), indipendentemente dalla quantità di memoria allocata.
mklement0

1
@ mklement0, hai ragione! L'ho appena provato con un file molto più grande di quello che avevo prima, e l'hashing sembra essere davvero il collo di bottiglia.
benroth

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

Leggi il file, aggiungi un numero casuale all'inizio di ogni riga, ordina il file su quei prefissi casuali, poi taglia i prefissi. One-liner che dovrebbe funzionare in qualsiasi shell semi-moderna.

EDIT: ha incorporato le osservazioni di Richard Hansen.


1
Funziona ed è una soluzione creativa, ma eliminerà gli spazi bianchi iniziali sulle linee.
Chris Lutz

@Chris sta cambiando l'ultimo taglio in | sed 's / ^ [^ \ t] * \ t //' dovrebbe risolverlo
bdonlan

Complimenti per la semplicità dell'approccio!
Shashikant Kore

3
+1 per la conformità POSIX (eccetto $RANDOM), ma -1 per la macellazione dei dati. La sostituzione while read fcon while IFS= read -r fimpedirà la readrimozione di spazi bianchi iniziali e finali (vedere questa risposta ) e impedirà l'elaborazione di barre rovesciate. L'uso di una stringa casuale di lunghezza fissa impedirà l' cuteliminazione degli spazi bianchi iniziali. Risultato: 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: Grazie, queste modifiche suggerite sono ovviamente appropriate, ho modificato il mio post.
ChristopheD

9

Una riga di testo per Python:

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

E per stampare solo una singola riga casuale:

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

Ma guarda questo post per gli svantaggi di Python random.shuffle(). Non funzionerà bene con molti (più di 2080) elementi.


5

In relazione alla risposta di Jim:

Il mio ~/.bashrccontiene quanto segue:

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

Con l'ordinamento di GNU coreutils, -R= --random-sort, che genera un hash casuale di ogni riga e ordina in base ad esso. L'hash randomizzato non sarebbe stato effettivamente utilizzato in alcune versioni locali in alcune versioni precedenti (buggy), causando la restituzione di un normale output ordinato, motivo per cui ho impostato LC_ALL=C.


In relazione alla risposta di Chris:

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

è un one-liner leggermente più corto. ( -Mmodule=a,b,cè una scorciatoia per-e 'use module qw(a b c);' .)

Il motivo per cui -inon funziona per lo shuffling sul posto è perché Perl si aspetta che ciò printavvenga nello stesso ciclo in cui il file viene letto, eprint shuffle <> non viene prodotto finché tutti i file di input non sono stati letti e chiusi.

Come soluzione più breve,

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

mescolerà i file sul posto. ( -nsignifica "avvolgere il codice in un while (<>) {...}ciclo; BEGIN{undef$/}fa sì che Perl operi su file alla volta invece che su righe alla volta, ed split/^/mè necessario perché $_=<>è stato implicitamente fatto con un intero file invece che con le righe.)


Ribadendo quel tipo -R non esiste su OS X, ma +1 per alcune ottime risposte Perl, e un'ottima risposta in generale.
Chris Lutz

Potresti installare GNU coreutils su OS X, ma (come ho fatto in passato) devi stare attento a non rompere gli strumenti integrati ... Detto questo, OP è su Redhat Linux, che ha sicuramente GNU standard di coreutils.
effimero

3

Quando installo coreutils con homebrew

brew install coreutils

shufdiventa disponibile come n.


brew ha prefisso tutti i comandi con gcosì è shufdiventato gshufper me.
Jörn

^ È perché non sono POSIX o sono semplicemente completamente fuori?
Dave Liu

1

Mac OS X con DarwinPorts:

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

1

FreeBSD ha la sua utilità casuale:

cat $file | random | ...

È in / usr / games / random, quindi se non hai installato giochi, sei sfortunato.

Potresti considerare l'installazione di porte come textproc / rand o textproc / msort. Questi potrebbero essere disponibili su Linux e / o Mac OS X, se la portabilità è un problema.


-1

Su OSX, prendendo le ultime da http://ftp.gnu.org/gnu/coreutils/ e qualcosa di simile

./configure make sudo make install

... dovrebbe darti / usr / local / bin / sort --random-sort

senza rovinare / usr / bin / sort


questo non ha funzionato per me su OSX (10.7). Ho "configura: errore: il compilatore C non può creare eseguibili".
Dolan Antenucci

@dolan Controlla i tuoi permessi?
Benubird

-1

Oppure scaricalo da MacPorts:

$ sudo port install coreutils

e / o

$ /opt/local//libexec/gnubin/sort --random-sort
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.