dd: vários arquivos de entrada

13

Preciso concatenar pedaços de dois arquivos:

se eu precisasse concatenar arquivos inteiros, eu poderia simplesmente fazer

cat file1 file2 > output

Mas preciso pular primeiro 1 MB do primeiro arquivo e quero apenas 10 MB do segundo arquivo. Parece um trabalho para dd.

dd if=file1 bs=1M count=99 skip=1 of=temp1
dd if=file2 bs=1M count=10 of=temp2
cat temp1 temp2 > final_output

Existe a possibilidade de fazer isso em uma etapa? ou seja, sem a necessidade de salvar os resultados intermediários? Posso usar vários arquivos de entrada dd?

Martin Vegter
fonte

Respostas:

21

dd também pode escrever para stdout.

( dd if=file1 bs=1M count=99 skip=1
  dd if=file2 bs=1M count=10  ) > final_output
meuh
fonte
Esta é provavelmente a melhor maneira. O arquivo de saída não é fechado / reaberto (como é o caso oflag=append conv=notrunc), portanto, os sistemas de arquivos que fazem alocação atrasada (como o XFS) são menos propensos a decidir que o arquivo está sendo gravado quando ainda há mais.
Peter Cordes
@PeterCordes esse é um bom argumento, mas, desde que ddnão seja solicitado sync, a alocação atrasada não deve ocorrer imediatamente (a menos que a memória esteja fraca, nesse caso, nenhum dos métodos adiará a alocação).
Stephen Kitt
@StephenKitt: Você provavelmente está certo. Eu estava pensando na pré-localização especulativa do XFS , onde ele precisa detectar especialmente o padrão de acesso de fechar / reabrir (às vezes visto para arquivos de log).
Peter Cordes
3
Em shells como bashe mkshque não otimizam a bifurcação para o último comando em um subshell, você pode torná-lo um pouco mais eficiente substituindo o subshell por um grupo de comandos. Para outros shells, isso não deve importar, e a abordagem do subshell pode até ser um pouco mais eficiente, pois o shell não precisa salvar e restaurar o stdout.
Stéphane Chazelas
10

Eu não acho que você possa ler facilmente vários arquivos em uma única ddinvocação, mas você pode acrescentar para criar o arquivo de saída em várias etapas:

dd if=file1 bs=1M count=99 skip=1 of=final_output
dd if=file2 bs=1M count=10 of=final_output oflag=append conv=notrunc

Você precisa especificar ambos conv=notrunce oflag=append. O primeiro evita truncar a saída, o segundo começa a gravar a partir do final do arquivo existente.

Stephen Kitt
fonte
8

Tenha em mente que ddé uma interface de cru para a read(), write()e lseek()chamada de sistema. Você pode usá-lo apenas com confiabilidade para extrair blocos de dados de arquivos regulares, dispositivos de bloco e alguns dispositivos de caracteres (como /dev/urandom), ou seja, arquivos para os quais read(buf, size)é garantido que retorne sizeenquanto o final do arquivo não for atingido.

Para tubos, soquetes e a maioria dos dispositivos de caracteres (como ttys), você não tem essa garantia, a menos que faça read()s do tamanho 1 ou use a ddextensão GNU iflag=fullblock.

Então:

{
  gdd < file1 bs=1M iflag=fullblock count=99 skip=1
  gdd < file2 bs=1M iflag=fullblock count=10
} > final_output

Ou:

M=1048576
{
  dd < file1 bs=1 count="$((99*M))" skip="$M"
  dd < file2 bs=1 count="$((10*M))"
} > final_output

Ou com conchas com suporte embutido para um operador de busca como ksh93:

M=1048576
{
  command /opt/ast/bin/head -c "$((99*M))" < file1 <#((M))
  command /opt/ast/bin/head -c "$((10*M))" < file2
}

Ou zsh(supondo que você headsuporte a -copção aqui):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output
Stéphane Chazelas
fonte
Você realmente precisa das aspas? O resultado não será sempre um número inteiro?
Steven Penny
@StevenPenny, deixar a expansão sem aspas é pedir ao shell para dividir + glob, o que não faria sentido aqui. A peça dividida sendo feita com o valor atual de $IFS. Independentemente do conteúdo da variável / expansão. Veja também as implicações de segurança de esquecer de citar uma variável na festança conchas / POSIX
Stéphane Chazelas
@ Stéphane Chazelas - no primeiro exemplo, você está usando, em gddvez de dd. Isso é um erro de digitação ou é intencional?
Martin Vegter
3

Com um bash ism e um funcionalmente "uso inútil de gato ", mas mais próximo da sintaxe que o OP usa:

cat <(dd if=file1 bs=1M count=99 skip=1) \
    <(dd if=file2 bs=1M count=10) \
   > final_output

(Dito isto, a resposta de Stephen Kitt parece ser o método mais eficiente possível.)

agc
fonte
3
A rigor, <(...)é um kshismo que é copiado zshe bashcopiado.
Stéphane Chazelas