dd vs cat - o dd ainda é relevante hoje em dia?

122

Recentemente, percebi que podemos usar cattanto quanto dd, e na verdade é mais rápido do quedd

Sei que isso ddfoi útil para lidar com fitas em que o tamanho do bloco realmente importava na correção, não apenas no desempenho. Nestes dias, porém, existem situações em que ddpodemos fazer algo catque não podemos? (Aqui consideraria irrelevante uma diferença de desempenho de menos de 20%.)

Exemplos concretos seriam legais!

kizzx2
fonte
1
Veja esta pergunta SO para um exemplo concreto.
Camh

Respostas:

156

Na aparência, ddé uma ferramenta de um sistema operacional IBM que mantém sua aparência externa (sua passagem de parâmetros), que executa algumas funções muito raramente usadas (como conversões EBCDIC para ASCII ou reversão de endianismo ... não é uma necessidade comum atualmente).

Eu achava que ddera mais rápido copiar grandes blocos de dados no mesmo disco (devido ao uso mais eficiente do buffer), mas isso não é verdade , pelo menos nos sistemas Linux atuais.

Eu acho que algumas das ddopções são úteis ao lidar com fitas, onde a leitura é realmente realizada em blocos (os drivers de fita não escondem os blocos no meio de armazenamento da mesma forma que os drivers de disco). Mas eu não sei os detalhes.

Uma coisa ddque pode ser feita (facilmente) por qualquer outra ferramenta POSIX é obter os primeiros N bytes de um fluxo. Muitos sistemas podem fazer isso com head -c 42, mas head -c, embora comuns, não estejam no POSIX (e não estão disponíveis hoje, por exemplo, no OpenBSD). ( tail -cé POSIX.) Além disso, mesmo onde head -cexiste, ele pode ler muitos bytes da fonte (porque usa o buffer interno do stdio), o que é um problema se você estiver lendo um arquivo especial no qual apenas a leitura tem efeito. (Os coreutils atuais do GNU leem a contagem exata com head -c, mas o FreeBSD e o NetBSD usam o stdio.)

De maneira mais geral, ddfornece uma interface para a API do arquivo subjacente, única entre as ferramentas do Unix: somente ddpode sobrescrever ou truncar um arquivo a qualquer momento ou procurar em um arquivo. (Essa é dda capacidade única e é grande; por incrível que pareça, ddé mais conhecida pelas coisas que outras ferramentas podem fazer.)

  • A maioria das ferramentas Unix sobrescreve o arquivo de saída, ou seja, apaga seu conteúdo e inicia-o do zero. Isso é o que acontece quando você também usa o >redirecionamento no shell.
  • Você pode anexar ao conteúdo de um arquivo com >>redirecionamento no shell ou com tee -a.
  • Se você deseja reduzir um arquivo removendo todos os dados após um certo ponto , isso é suportado pelo kernel subjacente e pela API C por meio da truncatefunção, mas não exposto por nenhuma ferramenta de linha de comando, excetodd :

    dd if=/dev/null of=/file/to/truncate seek=1 bs=123456  # truncate file to 123456 bytes
    
  • Se você deseja sobrescrever dados no meio de um arquivo, novamente, isso é possível na API de underyling, abrindo o arquivo para gravação sem truncar (e chamando lseekpara mover para a posição desejada, se necessário), mas só ddpode abrir um arquivo sem truncar ou anexar ou procurar no shell ( exemplo mais complexo ).

    # zero out the second kB block in the file (i.e. bytes 1024 to 2047)
    dd if=/dev/zero of=/path/to/file bs=1024 seek=1 count=1 conv=notrunc
    

Então ... Como ferramenta de sistema, ddé praticamente inútil. Como uma ferramenta de processamento de texto (ou arquivo binário), é bastante valiosa!

Gilles
fonte
Aceito porque acho que explica a essência das outras respostas ( trunce de seekser utilizável dd).
Kizzx2
2
Mais um uso especial: ddpode ler dados binários de descritores de arquivos não inseparáveis ​​sem destruir potencialmente os dados não lidos devido ao buffer do stdio. Veja aqui um exemplo: etalabs.net/sh_tricks.html
R ..
2
@R ..: Sim. No GNU coreutils 6.10, head -c Nchama reade nunca vai além de N. No NetBSD 5.1, head -cchama getc. No FreeBSD 7.4, head -cchama fread.
Gilles
1
O Coreutils ddtambém expõe O_DIRECT (etc.) ao script de shell, que também acho único.
Derobert
1
O Coreutils truncatepermite truncar ou estender arquivos, eliminando assim outro uso do dd.
dcoles
22

O ddcomando inclui muitas opções que o gato não pode acomodar. Talvez em seus casos de uso, cat seja um substituto viável, mas não seja um substituto de dd.

Um exemplo seria usar ddpara copiar parte de algo, mas não a coisa toda. Talvez você queira extrair alguns bits do meio de uma imagem iso ou da tabela de partição de um disco rígido com base em um local conhecido no dispositivo. Com ddvocê pode especificar as opções de início, parada e quantidade que permitem essas ações.

Essas opções o ddtornam indispensável para manipulação de dados refinada, enquanto cat* só pode operar em objetos, dispositivos ou fluxos de arquivos inteiros.

* Conforme observado por Gilles nos comentários, é possível combinar catcom outras ferramentas para isolar partes de algo, mas catainda opera em todo o objeto.

Caleb
fonte
5
ddrealmente não tem nada a ver com dispositivos de baixo nível, ele precisa de uma entrada /devcomo as outras. Você pode copiar uma partição inteira com cat, ou parte dela com tail +c $(($start+1)) | head -c $count.
Gilles
16
Claro. ;-) E quando eu alimentar uma imagem de disco de 1.6 TB cat | head | tailpara buscar os últimos MBs, o disco giratório sugará a lua para mais perto da Terra.
Caleb
2
@Gilles Desculpe, eu quis dizer que meu uso do termo "nível baixo" não era uma dicção muito boa, embora eu estivesse me referindo a dados em dispositivos, não dispositivos. Talvez "manipulação de dados sintonizada" seja melhor do que "manipulação de dados de baixo nível".
Caleb
21

Ninguém mencionou ainda que você pode usar o dd para criar arquivos esparsos , embora truncatetambém possa ser usado para a mesma finalidade.

dd if=/dev/zero of=sparse-file bs=1 count=1 seek=10GB

Isso é quase instantâneo e cria um arquivo grande arbitrário que pode ser usado como um arquivo de loopback, por exemplo:

loop=`losetup --show -f sparse-file`
mkfs.ext4 $loop
mkdir myloop
mount $loop myloop

O bom é que, inicialmente, ele usa apenas um único bloco de espaço em disco e depois cresce apenas conforme necessário (a formatação ext4 de um arquivo de 10 GB consome 291 MB no meu sistema). Use dupara ver quanto espaço em disco é realmente usado - lsinforma apenas o tamanho máximo para o qual o arquivo pode crescer.

Lauritz V. Thaulow
fonte
4
ls -lsmostra o tamanho escasso.
jmtd
2
Seu comando grava um byte inútil no arquivo. dd of=sparse-file bs=1 count=0 seek=10Gseria equivalente a truncate -s 10GB sparse-file. Desconcertante suficiente, truncatee ddtem interpretação exata oposto GBvs. G...
frostschutz
5
@frostschutz: man dddiz: MB =1000*1000, M =1024*1024e assim por diante. E man truncatediz:, MB 1000*1000, M 1024*1024então não há diferença. Eu uso ambos dde a truncatepartir dos GNU coreutils. Você deveria fazer isso também! :-)
erik 06/06
@erik: Obrigado pela correção. Se não foi alterado recentemente, devo confundi-lo com outra coisa de alguma forma.
Frostschutz 6/06/2013
10

Substituir segmentos específicos de um disco rígido por algo é um exemplo comum. Por exemplo, você pode excluir seu MBR usando este comando:

dd if=/dev/zero of=/dev/sda bs=446 count=1

Além disso, você pode criar arquivos vazios com ele (por exemplo, para imagens de disco de loop):

dd if=/dev/zero of=10mb.file bs=1024k count=10
XQYZ
fonte
Como um aparte, que segundo comando é a maneira mais rápida que eu conheço para utilizar até 10MB
Kevin M
3
@ Kevin: Mais rápido que head -c? Por favor, compartilhe uma referência !
Gilles
9

ddé muito útil para fazer backup do setor de inicialização de um disco rígido ou outro dispositivo de armazenamento ( dd if=/dev/sda of=boot_sector.bin bs=512 count=1) e depois reescrevê-lo ( dd if=boot_sector.bin of=/dev/sda). É igualmente útil para fazer backup dos cabeçalhos de volumes criptografados.

catpode ser capaz de fazer isso, mas eu não confiaria na parte de reescrever. É difícil conseguir catler / gravar apenas um determinado número de bytes.

LawrenceC
fonte
5

Recentemente, tive motivos para clonar várias partições de 100s de GB pela primeira vez na minha história de linux (cf cp -arou rsyncque me serviram muitas vezes). Claro que me virei para dd'porque todo mundo sabe que é isso que você usa ... e fiquei horrorizado com o desempenho. Um pouco de pesquisa no Google logo me levou a ddrescueusá-lo algumas vezes agora e funciona muito bem (muito mais rápido que o dd).

timday
fonte
1
ddrescueé ótimo, especialmente para obter dados de discos com falha.
Ryenus #
5

Aqui estão alguns truques que eu inventei ao longo dos anos.

Recortar e colar no modo tty ou não interativo hostil

Se você estiver em uma situação em que EOF / ^ D / ^ F não for detectado, use dd para transferir arquivos de texto para um host. Uma vez que ele irá parar de ler automaticamente após uma quantidade especificada de bytes.

Usei isso recentemente no ano passado, durante um exercício de segurança em que conseguimos obter shells não-tty em um host remoto e precisávamos transferir arquivos.

Na verdade, eu até criei alguns arquivos binários codificando-os em base64 e usando um script de decodificação de base64 lento, mas confiável.

dd of=textfile.txt bs=1 count=<size_of_data_in_paste_buffer>

Um truque super bacana é que, enquanto o dd estiver em execução, se você enviar um sinal USR1, ele emitirá seu status atual (bytes lidos, bytes por segundo ..)

Filtro de estado de rendimento universal

Eu escrevi isso para atuar como um filtro de progresso do bash puro para qualquer programa que emita dados através do stdout. (Nota: praticamente qualquer coisa emitirá dados através do stdout - para programas que não o fazem, você pode trapacear se eles não vomitarem usando o / dev / stdout como um nome de arquivo. Mas a idéia é basicamente, toda vez que você obtém o X quantidade de bytes, imprimir marcas de hash (como o FTP da velha escola quando o modo de hash estava ativado)

(Nota) A coisa do arquivo de progresso é esfarrapada, isso era principalmente uma prova de conceito. Se eu refizesse, usaria apenas uma variável.

 dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
                | grep --line-buffered -E '[[:digit:]]* bytes' \
                | awk '{ print $1 }' >> ${PROGRESS} &

 while [[ $(pidof dd) -gt 1 ]]; do

        # PROTIP: You can sleep partial seconds
        sleep .5

        # Force dd to update us on it's progress (which gets
        # redirected to $PROGRESS file.    
        pkill -USR1 dd
        local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
        local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))

        if [ $XFER_BLKS -gt 0 ]; then
                printf "#%0.s" $(seq 0 $XFER_BLKS)
                BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
        fi
done

arquivos de fatia e dados usando manipuladores de arquivos de shell anônimos

Aqui está um exemplo extremamente pseudo-código de como você pode ter um arquivo tar assinado que pode ser extraído sem erros, fornecendo entrada tar através de um tratamento de arquivos anônimo - sem usar nenhum arquivo tmp para armazenar dados parciais do arquivo.

generate_hash() {
    echo "yay!"
}

# Create a tar file, generate a hash, append it to the end
tar -cf log.tar /var/log/* 2>/dev/null
TARFILE_SIZE=$(stat -f "%z" log.tar)
SIGNATURE=$(generate_hash log.tar)
echo $SIGNATURE >>log.tar

# Then, later, extract without getting an error..

tar xvf <(dd if=$OLDPWD/log.tar bs=1 count=${TARFILE_SIZE})

O tl; dr é: acho que o dd é incrivelmente útil. E esses são apenas os três exemplos em que consigo pensar.

synthesizerpatel
fonte
4

Você pode redirecionar algum conteúdo de saída. É particularmente útil se você precisar escrever com sudo:

echo some_content | sudo dd status=none of=output.txt

Além disso sudo, é equivalente a:

echo some_content > output.txt

ou para isso:

echo some_content | sudo tee output.txt > /dev/null
Alexey
fonte