Como posso randomizar as linhas em um arquivo usando ferramentas padrão no Red Hat Linux?


102

Como posso randomizar as linhas em um arquivo usando ferramentas padrão no Red Hat Linux?

Eu não tenho o shufcomando, então estou procurando por algo como um perlou awkuma linha que realize a mesma tarefa.


1
Eu fiz quase a mesma pergunta [ stackoverflow.com/questions/286640/…
Steve Schnepp


Eu considero o gcc uma ferramenta padrão em qualquer Linux. ; D
msb

Respostas:


64

E você ganha uma linha de Perl!

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

Ele usa um módulo, mas o módulo faz parte da distribuição de código Perl. Se isso não for bom o suficiente, você pode considerar lançar o seu próprio.

Tentei usar isso com o -isinalizador ("editar no local") para que ele edite o arquivo. A documentação sugere que deveria funcionar, mas não funciona. Ele ainda exibe o arquivo embaralhado em stdout, mas desta vez exclui o original. Eu sugiro que você não use.

Considere um 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

Não testado, mas espero que funcione.


Para fazer backup do arquivo original, você pode sufocar uma extensão para o sinalizador -i [ perldoc.perl.org/perlrun.html]
Steve Schnepp

Eu geralmente sou um fã Perl, mas deparei com este exemplo de rubi que tem a vantagem de ser mais curto: ruby -e 'puts STDIN.readlines.shuffle'. Seria necessário testar em grandes entradas para ver se a velocidade é comparável. (também funciona no OS X)
mivk de

por comentário abaixo, shufcarrega tudo na memória, por isso não funciona com um arquivo realmente grande (o meu é de aproximadamente 300 GB tsv). Este script perl falhou no meu também, mas sem nenhum erro, exceto Killed. Alguma ideia se a solução perl está carregando tudo na memória também, ou há algum outro problema que estou encontrando?
seth127

211

Hum, não vamos esquecer

sort --random-sort

1
Bem, estou usando o gnu-coreutils 7.1 (instalação padrão do gentoo), que tem classificação com esta opção, não tenho certeza de quando apareceu ou se está em outras implementações.
Jim T

1
O recurso foi lançado em 10 de dezembro de 2005, o lançamento seguinte foi 5.94, então suponho que esteja disponível desde essa versão.
Jim T

41
No OS X você pode instalar gnu coreutils com homebrew: brew install coreutilsTodos os utilitários são prefixados com ag so: gsort --random-sortou gshuffuncionarão como esperado
mike

3
+1 @mike. Eu uso Macports e também tinha gsorte gshufinstalei quando fizport install coreutils
Noah Sussman

10
Esta solução só é boa se suas falas não tiverem repetições. Se o fizerem, todas as instâncias dessa linha aparecerão uma ao lado da outra. Considere usar em shufvez disso (no Linux).
Ali J

118

shuf é a melhor maneira.

sort -Ré dolorosamente lento. Eu apenas tentei classificar o arquivo de 5 GB. Desisti após 2,5 horas. Então shufresolveu em um minuto.


Isso é ótimo. Parece estar no GNU coreutils.
ariddell

4
Suspeito que o motivo da sort -Rlentidão é que calcula um hash para cada linha. Dos documentos: " Classifique por hash das chaves de entrada e, em seguida, classificando os valores de hash. "
Joe Flynn

13
cuidado, shufcarrega tudo na memória.
jfs

1
@benroth: Pelo que eu posso dizer, com contagens de entrada realmente grandes, aumentar a memória pode ajudar um pouco , mas ainda é lento no geral. Em meus testes, classificar um arquivo de entrada de 1 milhão de linhas criado com seq -f 'line %.0f' 1000000levou o mesmo, muito tempo para processar (muito, muito mais do que com shuf), não importa quanta memória eu aloquei.
mklement0

1
@ mklement0, você está certo! Eu apenas tentei com um arquivo muito maior do que o que tinha antes, e o hashing parece ser o gargalo, de fato.
Benroth

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

Leia o arquivo, prefixe cada linha com um número aleatório, classifique o arquivo com esses prefixos aleatórios e corte os prefixos depois. One-liner que deve funcionar em qualquer shell semi-moderno.

EDITAR: incorporou as observações de Richard Hansen.


1
Isso funciona e é uma solução criativa, mas excluirá os espaços em branco iniciais das linhas.
Chris Lutz

@Chris alterando o último corte para | sed 's / ^ [^ \ t] * \ t //' deve corrigir isso
bdonlan

Parabéns pela simplicidade da abordagem!
Shashikant Kore

3
+1 para conformidade POSIX (exceto para $RANDOM), mas -1 para massacrar os dados. Substituir while read fpor while IFS= read -r fimpedirá a readremoção de espaços em branco à esquerda e à direita (veja esta resposta ) e impedirá o processamento de barras invertidas. Usar uma string aleatória de comprimento fixo impedirá a cutexclusão de espaços em branco iniciais. 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: Obrigado, essas mudanças sugeridas são obviamente apropriadas, eu editei minha postagem.
ChristopheD

9

Um one-liner para python:

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

E para imprimir apenas uma única linha aleatória:

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

Mas veja este post para as desvantagens do python random.shuffle(). Não funcionará bem com muitos (mais de 2080) elementos.


5

Relacionado à resposta de Jim:

Meu ~/.bashrccontém o seguinte:

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

Com GNU coreutils's sort, -R= --random-sort, que gera um hash aleatório de cada linha e classifica por ele. O hash aleatório não seria realmente usado em algumas localidades em algumas versões mais antigas (com erros), fazendo com que retornasse a saída classificada normal, que é o motivo pelo qual eu configurei LC_ALL=C.


Relacionado à resposta de Chris:

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

é uma linha ligeiramente mais curta. ( -Mmodule=a,b,cé uma abreviação de -e 'use module qw(a b c);'.)

A razão de dar a ele um simples -inão funciona para embaralhar no local é porque Perl espera que printaconteça no mesmo loop em que o arquivo está sendo lido, e print shuffle <>não sai até que todos os arquivos de entrada tenham sido lidos e fechados.

Como uma solução alternativa mais curta,

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

irá embaralhar os arquivos no local. ( -nsignifica "envolver o código em um while (<>) {...}loop; BEGIN{undef$/}faz o Perl operar em arquivos por vez em vez de linhas por vez, e split/^/mé necessário porque $_=<>foi feito implicitamente com um arquivo inteiro em vez de linhas.)


Reiterando que o tipo -R não existe no OS X, mas +1 para algumas ótimas respostas Perl, e uma ótima resposta em geral.
Chris Lutz de

Você poderia instalar GNU coreutils no OS X, mas (como eu fiz no passado) você deve ter cuidado para não quebrar as ferramentas embutidas ... Dito isto, OP está no Redhat Linux, que definitivamente tem GNU padrão coreutils.
epemiente

3

Quando eu instalo coreutils com homebrew

brew install coreutils

shuftorna-se disponível como n.


brew prefixou todos os comandos com gso shuftornou - se gshufpara mim.
Jörn

^ Isso é porque eles não são POSIX ou estou totalmente maluco?
Dave Liu

1

Mac OS X com DarwinPorts:

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

1

O FreeBSD tem seu próprio utilitário aleatório:

cat $file | random | ...

Está em / usr / games / random, portanto, se você não instalou os jogos, está sem sorte.

Você pode considerar a instalação de portas como textproc / rand ou textproc / msort. Eles podem estar disponíveis no Linux e / ou Mac OS X, se a portabilidade for uma preocupação.


-1

No OSX, baixando o mais recente de http://ftp.gnu.org/gnu/coreutils/ e algo como

./configure make sudo make install

... deve fornecer a você / usr / local / bin / sort --random-sort

sem bagunçar / usr / bin / sort


isso não funcionou para mim no OSX (10.7). Recebi "configurar: erro: o compilador C não pode criar executáveis".
Dolan Antenucci

@dolan Verifique suas permissões?
Benubird

-1

Ou obtenha-o no MacPorts:

$ sudo port install coreutils

e / ou

$ /opt/local//libexec/gnubin/sort --random-sort
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.