dd: vários arquivos de entrada

13

Eu preciso concatenar partes de dois arquivos:

se eu precisasse concatenar arquivos inteiros, eu poderia simplesmente fazer

cat file1 file2 > output

Mas eu preciso pular primeiro 1 MB do primeiro arquivo, e só quero 10 MB do segundo arquivo. Soa como 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 um passo? ou seja, sem a necessidade de salvar os resultados intermediários? Posso usar vários arquivos de entrada em dd ?

    
por Martin Vegter 02.05.2016 / 10:12

4 respostas

20

dd também pode gravar no stdout.

( dd if=file1 bs=1M count=99 skip=1
  dd if=file2 bs=1M count=10  ) > final_output
    
por 02.05.2016 / 13:36
10

Não acho que você possa ler facilmente vários arquivos em uma única invocação de dd , mas é possível anexar 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 conv=notrunc e oflag=append . O primeiro evita truncar a saída, o segundo começa a escrever a partir do final do arquivo existente.

    
por 02.05.2016 / 10:18
8

Lembre-se de que dd é uma interface simples para a chamada de sistema read() , write() e lseek() . Você só pode usá-lo de forma confiável para extrair partes de dados de arquivos comuns, dispositivos de bloqueio e alguns dispositivos de caractere (como /dev/urandom ), ou seja, arquivos para os quais read(buf, size) tem garantia de retornar size desde o final do arquivo não é alcançado.

Para pipes, soquetes e a maioria dos dispositivos de caractere (como o ttys), você não tem essa garantia, a menos que você use read() s de tamanho 1 ou use o GNU dd extension 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 shells com suporte integrado 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 (assumindo que o seu head suporta a opção -c aqui):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output
    
por 02.05.2016 / 17:59
3

Com um bash ism , e um funcionalmente "uso inútil de cat ", 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 possível eficiente ).

    
por 02.05.2016 / 17:39

Tags