Imprima linhas aleatórias respeitando a ordem do arquivo de origem

6

Eu tenho um arquivo de texto grande (~ 500K linhas) com frases curtas (par de palavras longas). Além disso, há alguma marcação XML na maioria das linhas. Finalmente, o arquivo de texto foi classificado antes , a marcação foi adicionada! Adicionar a marcação XML altera a classificação alfabética, mas isso é desejado.

Minha pergunta é: Como posso imprimir linhas aleatórias respeitando a ordem do arquivo de origem?

Eu sei que eu poderia apenas usar o comando shuf e classificar o resultado. O problema é que a marcação vai atrapalhar o tipo.

Eu também poderia escrever um script python que carrega o arquivo de texto em uma lista, gera alguns números aleatórios, os classifica e os usa como índices para extrair as linhas. Se possível, eu preferiria ferramentas de linha de comando padrão * nix.

Dados da amostra:

<CITY>anaconda</CITY> city is in <STATE>montana</STATE>
let's go to <CITY>rome</CITY>
please find <CITY>berlin</CITY>
where is <CITY>cairo</CITY> in <COUNTRY>egypt</COUNTRY>

Por exemplo, seria ótimo se eu pudesse puxar a linha 2 e 3. As linhas 1,3 e 4 também são boas. Se eu pegar a linha 3, 1 e 4, isso não é bom.

    
por Vladislavs Dovgalecs 14.08.2015 / 19:16

3 respostas

16

Use isto:

nl file | shuf -n2 | sort -n | cut -f2-
  • nl para numerar as linhas,
  • shuf para misturar e limitar a saída a duas linhas ( -n ),
  • sort para reconstruir o pedido original,
  • e cut para remover a numeração de nl .

Ele imprimirá 2 linhas do seu arquivo na ordem original do arquivo. Use shuf -n X , onde X pode ser qualquer número.

    
por 14.08.2015 / 19:30
6

A seleção de uma linha aleatória de um arquivo sem ordenação (ou mesmo saber quantas linhas existem!) é abordada em "A arte da programação de computadores", Volume 2, Seção 3.4.2, de Donald E. Knuth. Isso é trivial para implementar, por exemplo:

(echo foo; echo bar; echo zot) \
| perl -nle 'rand $. < 1 && ( $line = $_ ); END { print $line }'

Ou tente shuf , que permite a seleção de um certo número de linhas, embora possa, portanto, exigir mais memória do que o algoritmo Knuth de seleção única.

    
por 14.08.2015 / 19:30
5

Você pode fazer isso com um loop while e $ RANDOM como:

while read line; do
    if ((RANDOM%2)); then
        echo $line;
    fi;
done < _path_

que imprime cerca de metade das linhas, que você pode controlar com a condição em if

    
por 14.08.2015 / 19:32