Resumo: dd
é uma ferramenta irritante que é difícil de usar corretamente. Não o use, apesar dos inúmeros tutoriais que lhe dizem isso. dd
tem uma vibração de "unix street cred", mas se você realmente entende o que está fazendo, saberá que não deve tocá-lo com uma vara de três metros.
dd
faz uma única chamada para a chamada do read
sistema por bloco (definida pelo valor de bs
). Não há garantia de que a read
chamada do sistema retorne tantos dados quanto o tamanho do buffer especificado. Isso costuma funcionar para arquivos regulares e dispositivos de bloco, mas não para pipes e alguns dispositivos de caracteres. Consulte Quando o dd é adequado para copiar dados? (ou, quando são lidos () e gravados () parciais) para obter mais informações. Se a read
chamada do sistema retornar menos de um bloco completo, dd
transferirá um bloco parcial. Ele ainda copia o número especificado de blocos, portanto, a quantidade total de bytes transferidos é menor que o solicitado.
O aviso sobre uma "leitura parcial" diz exatamente isso: uma das leituras foi parcial, portanto dd
transferiu um bloco incompleto. Na contagem de blocos, +1
significa que um bloco foi lido parcialmente; como a contagem de saída é +0
, todos os blocos foram gravados como lidos.
Isso não afeta a aleatoriedade dos dados: todos os bytes dd
gravados são bytes dos quais eles são lidos /dev/urandom
. Mas você tem menos bytes do que o esperado.
O Linux /dev/urandom
acomoda solicitações grandes e arbitrárias (fonte: extract_entropy_user
in drivers/char/random.c
), portanto dd
normalmente é seguro ao ler a partir dele. No entanto, a leitura de grandes quantidades de dados leva tempo. Se o processo receber um sinal, a read
chamada do sistema retornará antes de preencher seu buffer de saída. Esse é um comportamento normal, e os aplicativos devem chamar read
em um loop; dd
não faz isso, por razões históricas ( dd
as origens são obscuras, mas parece ter começado como uma ferramenta para acessar fitas, que têm requisitos peculiares e nunca foi adaptada para ser uma ferramenta de uso geral). Quando você verifica o progresso, isso envia ao dd
processo um sinal que interrompe a leitura. Você pode escolher entre saber quantos bytesdd
será copiado no total (lembre-se de não interrompê-lo - sem verificação de progresso, sem suspensão) ou sabendo quantos bytes dd
foram copiados até agora; nesse caso, você não pode saber quantos bytes serão copiados.
A versão do dd
GNU coreutils (como encontrada no Linux não incorporado e no Cygwin) possui uma flag fullblock
que diz dd
para chamar read
um loop (e o mesmo para write
) e, portanto, sempre transfere blocos completos. A mensagem de erro sugere que você o use; você deve sempre usá-lo (nos sinalizadores de entrada e de saída), exceto em circunstâncias muito especiais (principalmente ao acessar fitas) - se você usar dd
, ou seja: geralmente existem soluções melhores (veja abaixo).
dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000
Outra maneira possível de ter certeza do que dd
fará é passar o tamanho de um bloco de 1. Então, você pode dizer quantos bytes foram copiados da contagem de blocos, embora não tenha certeza do que acontecerá se um read
for interrompido antes de ler o primeiro byte (o que não é muito provável na prática, mas pode acontecer). No entanto, mesmo que funcione, isso é muito lento.
O conselho geral sobre o uso dd
é não usardd
. Embora dd
seja frequentemente anunciado como um comando de baixo nível para acessar dispositivos, na verdade não existe: toda a mágica acontece na parte do arquivo do dispositivo /dev/…
, dd
é apenas uma ferramenta comum com um alto potencial de uso indevido, resultando em perda de dados . Na maioria dos casos, existe uma maneira mais simples e segura de fazer o que você deseja, pelo menos no Linux.
Por exemplo, para ler um certo número de bytes no início de um arquivo, basta chamar head
:
head -c 1000000m </dev/urandom >file
Fiz uma referência rápida na minha máquina e não observei nenhuma diferença de desempenho entre dd
um tamanho de bloco grande e head
.
Se você precisar pular alguns bytes no início, entre tail
em head
:
dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output
Se você quiser ver o progresso, ligue lsof
para ver o deslocamento do arquivo. Isso funciona apenas em um arquivo regular (o arquivo de saída no seu exemplo), não em um dispositivo de caractere.
lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1
Você pode ligar pv
para obter um relatório de progresso (melhor que dd
o), às custas de um item adicional no pipeline (em termos de desempenho, é quase imperceptível).