Como preencher um arquivo com um fluxo de / dev / urandom com um número especificado de linhas?

4

Estou tentando preencher um arquivo com uma sequência de 0 e 1s aleatórios com um número de linhas definido pelo usuário e um número de caracteres por linha.

o primeiro passo é obter um fluxo aleatório de 0 e 1s:

cat /dev/urandom | tr -dc 01

tentei preencher um arquivo com esse fluxo (e finalizar o processo de preenchimento por ctrl + c)

cat /dev/urandom | tr -dc 01 > foo

quando eu contar o número de linhas do arquivo foo assim criado, recebo 0 linhas.

cat foo | wc -l
0

Agora tentei controlar o fluxo, então criei um pipe nomeado e direcionei o fluxo para ele. Então eu fiz uma conexão com o pipe nomeado com o comando dd em vão espero controlar dessa forma a quantidade de caracteres por linha e número de linhas no arquivo.

makefifo namedpipe
cat /dev/urandom | tr -dc 01 > namedpipe
dd if=namedpipe of=foo bs=10 count=5

o arquivo foo de fato foi preenchido com 50 bytes de 0 e 1, mas o número de linhas ainda era 0.

Como posso resolvê-lo, eu acho que talvez eu tenha que inserir cada número de caracteres de uma nova linha no arquivo, mas se assim for, eu não sei como.

    
por Abdul Al Hazred 23.03.2015 / 00:58

4 respostas

8

Que tal fold ? Faz parte dos coreutils ...

$ tr -dc 01 < /dev/urandom | fold -w 30 | head -n 5
001010000111110001100101101101
000101110011011100100101111000
111010101011100101010110111001
111011000000000101111110110100
110011010111001110011010100011

Ou, se isso não estiver disponível, algum sabor de awk :

$ tr -dc 01 < /dev/urandom | awk \
$ for line in $(seq 1 5)
> do
>     echo $(tr -dc 01 < /dev/urandom | head -c 30)
> done
100101100111011110010010100000
000000010000010010110111101011
010000111110010010000000010100
001110110001111011101011001001
001010111011000111110001100110
=RT RS=.\{,30} | head -n 5 000100010010001110100110100111 101010010100100110111010001110 100011100101001010111101001111 010010100111100101101100010100 001101100000101001111011011000

Ou você pode fazer algo com um loop ...

$ tr -dc 01 < /dev/urandom | fold -w 30 | head -n 5
001010000111110001100101101101
000101110011011100100101111000
111010101011100101010110111001
111011000000000101111110110100
110011010111001110011010100011

Tenho certeza que existem outras maneiras ... Eu pensei que talvez o hexdump com um formato personalizado pudesse fazê-lo, mas aparentemente não ...;)

    
por 23.03.2015 / 01:20
4
LC_ALL=C </dev/urandom \
tr '
1101001010
1100001001
1101110100
1011011000
1011110100
1+0 records in
0+1 records out
55 bytes (55 B) copied, 0.00176591 s, 31.1 kB/s
-7' '[0*128][1*]' | dd ibs=50 cbs=10 conv=unblock count=1

Isso converterá todos os bytes ascii de entrada (que serão todos os bytes porque LC_ALL=C está especificado) em um dos 0 ou 1 em uma distribuição par. Os primeiros 128 bytes entre 7 e 0-7 são convertidos em zeros e dd em uns - e assim você pode usar todos os bytes de entrada e ainda gerar seqüências aleatoriamente ordenadas de apenas 1 ou 0.

Você estava certo em usar bs= , mas não precisa definir seu tamanho de bloco \n para obter 5 linhas de saída de 11 bytes (10 + count=1 ewline) uma peça. Em vez disso, você deve especificar um read() single ibs=50 para um bloco de entrada de cbs=10 bytes, que pode ser dividido em blocos de conversão de 5 conv=unblock sized e \n ed em cbs-size anexando dd ewline para cada bloco de conversão depois de remover todos os espaços à direita (dos quais você não tem nenhum) .

Então eu apenas corri e imprimi:

time (
LC_ALL=C </dev/urandom \
tr -dc 01 |
dd ibs=4k cbs=10 conv=unblock count=k|
grep \[^01])

Eu também aumentei um pouco a aposta para mostrar uma comparação de velocidade entre um método e outro e para demonstrar que a leitura de grep de um pipe não é um problema se você ler em um fator de bloqueio que considera para o tamanho do buffer do utilitário de gravação. Então eu fiz primeiro:

1024+0 records in
9011+1 records out
4613735 bytes (4.6 MB) copied, 25.8898 s, 178 kB/s
( LC_ALL=C tr -dc 01 < /dev/urandom |\
  dd ibs=4k cbs=10 conv=unblock count=k |...)\
0.80s user 25.42s system 101% cpu 25.921 total

... que não produziu saída no stdout (então dd não correspondia a nada além de 0 ou 1) e o seguinte em stderr:

time (
LC_ALL=C </dev/urandom \
tr '
1024+0 records in
9011+1 records out
4613735 bytes (4.6 MB) copied, 0.554202 s, 8.3 MB/s
( LC_ALL=C tr '
LC_ALL=C </dev/urandom \
tr '
1101001010
1100001001
1101110100
1011011000
1011110100
1+0 records in
0+1 records out
55 bytes (55 B) copied, 0.00176591 s, 31.1 kB/s
-7' '[0*128][1*]' | dd ibs=50 cbs=10 conv=unblock count=1
-7' '[0*128][1*]' \ < /dev/urandom|dd ibs=4k cbs=10 ...)\ 0.61s user 0.36s system 171% cpu 0.571 total
-7' '[0*128][1*]' | dd ibs=4k cbs=10 conv=unblock count=k| grep '[^01]')

As informações acima informam que o pipeline gastou 25,5 segundos aguardando as chamadas do sistema. Está bem. Mas também nos diz que read() lê todos os 1024 de seus registros de entrada de 4096 bytes completamente e nenhum deles foi truncado devido a um retorno inicial de tr - e isso é porque dd buffers transmitiram a saída em blocos de 4k.

De qualquer forma, fazer da outra maneira - ou converter todas as entradas aleatórias em um espectro de dispersão, foi o seguinte:

time (
LC_ALL=C </dev/urandom \
tr -dc 01 |
dd ibs=4k cbs=10 conv=unblock count=k|
grep \[^01])

Mais uma vez, não havia nada no stdout - então todos da saída de dd era um de um zero ou um ou uma nova linha - e isso em stderr:

1024+0 records in
9011+1 records out
4613735 bytes (4.6 MB) copied, 25.8898 s, 178 kB/s
( LC_ALL=C tr -dc 01 < /dev/urandom |\
  dd ibs=4k cbs=10 conv=unblock count=k |...)\
0.80s user 25.42s system 101% cpu 25.921 total

... que demonstra mais uma vez que tr lê todos os 1024 registros de entrada completos + 0 registros de entrada truncados, mas o tempo de processamento é significativamente diferente. dd e %code% são realmente capazes de trabalhar em paralelo aqui e, juntos, usam mais tempo total de usuário em núcleos separados do que o processo inteiro para concluir em apenas 6 segundos. Isso é um pouco mais rápido.

    
por 23.03.2015 / 07:11
1

Para adicionar uma nova linha durante o processo de geração, faça o seguinte:

{ process-without-terminating-newline ; echo ;} > outfile

Para adicioná-lo a um arquivo existente, faça o seguinte:

echo >> outfile
    
por 23.03.2015 / 01:14
1

then I tried to fill a file with this stream (and end the process of filling by ctrl+c)

cat /dev/urandom | tr -dc 01 > foo

when I count the numbers of lines of the so created foo file I get 0 lines.

cat foo | wc -l
0

Ambos cat e tr buffer de sua saída. Quando você pressionar Ctrl + C , todos os dados que ainda estiverem no buffer de um dos comandos serão perdidos. Você interrompeu os programas cedo o suficiente para que tr ainda não tivesse acumulado um valor de buffer completo, por isso não havia escrito nada.

Não use dd para ler a partir de dispositivos ou tubos de caracteres .

No Linux, você pode usar head para truncar dados após um determinado número de bytes.

i=0
while [ "$i" -lt "$number_of_lines" ]; do
  </dev/urandom tr -dc 01 | head -c "$bits_per_line"; echo
  i=$((i+1))
done >foo

Como alternativa, produza o número desejado de bytes e use fold para injetar novas linhas.

</dev/urandom tr -dc 01 |
fold -w "$bits_per_line" |
head -n "$number_of_lines"

Rejeitar todos os bytes que não sejam 0 ou 1 é bastante lento: você está rejeitando 127 / 128º das entradas. Não há nenhum utilitário padrão que produza saída na base 2, mas você pode usar od para produzir hexadecimal e converter dígito por dígito.

</dev/urandom od -An -tx1 |
sed 's/ //g; s/0/@@@@/g; s/1/@@@'/g; s/2/@@'@/g; s/3/@@''/g; s/4/@'@@/g; s/5/@'@'/g; s/6/@''@/g; s/7/@'''/g; s/8/'@@@/g; s/9/'@@'/g; s/[Aa]/'@'@/g; s/[Bb]/'@''/g; s/[Cc]/''@@/g; s/[Dd]/''@'/g; s/[Ee]/'''@/g; s/[Ff]/''''/g; y/@'/01/' |
fold -w "$bits_per_line" |
head -n "$number_of_lines"

Se você tiver xxd , poderá usá-lo para converter bytes em sua representação de base 2. Se o número de bits por linha for múltiplo de 8, você pode até mesmo usar sua opção -c para fazê-lo inserir novas linhas quando desejado e -l para fazê-lo parar após um número de linhas.

</dev/urandom xxd -b -c "$bytes_per_line" -l "$((bytes_per_line * number_of_lines))" |
sed -e 's/  .*//' -e 's/.*://'
    
por 23.03.2015 / 01:31