Efficient Use of dd (armazena muitos blocos, processa um de cada vez)

2

Dado um arquivo, preciso procurar o número de blocos que corresponde a um bloco de entrada $templateBlock de determinado tamanho $blockSize .

Qual é uma maneira eficiente de usar dd para realizar essa tarefa? O método a seguir é ruim e lento porque invoca dd muitas vezes.

while [ $i -lt $totalBlocks]; do
  dd if="$pathToFile" bs=$blockSize count=1 skip=$i | diff $templateBlock -
  # Increase $count if $? is 0
  # Increase $i by 1 
done

A melhor maneira provavelmente será para dd ler $totalSize e processar apenas $blockSize de cada vez para todas as coisas lidas. Dessa forma, só preciso chamar dd uma vez. Em outras palavras, tenha dd lido todos (ou muitos) blocos de uma vez, e eu posso processar cada bloco um de cada vez. É possível fazer isso?

Talvez algo assim:

dd if="$pathToFile" bs=$blockSize | for-each-block {
  diff $templateBlock -
  # Update $count if $? is 0
}

Idealmente, quero usar apenas utilitários de shell.
Em outras palavras, prefiro não ter que escrever um programa usando Python ou similar.

    
por nehcsivart 12.04.2016 / 02:34

2 respostas

2

Em um shell script, pode ser melhor usar cmp do GNU diffutils. Ele compara dados para você e pode até mesmo ignorar deslocamentos --ignore-initial=SKIP1:SKIP2 , então você pode executar cmp para cada deslocamento de setor, e ele sairá na primeira diferença que encontrar ... que é semi-eficiente, mas ainda assim, isso é MUITO cmp chama se você quiser executá-lo para cada setor ...

Você também pode usar grep -abo ou strings -t d para encontrar possíveis candidatos de deslocamento de byte, mas isso depende do padrão real que você está procurando. A vantagem para estes seria uma chamada de programa para pesquisar a coisa toda, em oposição a milhares de chamadas (uma por setor).

A menos que você encontre um utilitário de linha de comando que apenas faça todo o trabalho para você, você não pode superar um pequeno script C / Go / Python que pesquisa tudo de uma só vez conforme suas necessidades. .

Sua idéia de script também funciona, mas significa apenas chamar dd (ou read , ou qualquer outra coisa) dentro do loop para ler um bloco de stdin por vez, provavelmente é mais lento que antes ...

    
por 12.04.2016 / 03:51
2

Você pode usar o comando split para executar um "filtro" em partes sucessivas de um arquivo e gravar um filtro usando cmp , echo e true para obter uma nova linha para cada correspondência bem-sucedida. então use wc para contar estes. Por exemplo, se $F for o arquivo, $TB o arquivo de bloco de modelo e $SZ do tamanho do bloco de modelo, ele poderá se parecer com a seguinte linha de comando:

$ split -b $SZ --filter="cmp $TB >& /dev/null && echo ; true" $F | wc -l

Observe o true que garante que a linha de comando do filtro seja bem-sucedida e, para salvar a digitação, você pode usar : , embora isso não melhore a legibilidade.

Note também o redirecionamento de todas as saídas de cmp , ou seja, tanto o stdout quanto o stderr, já que apenas o código de retorno é de interesse.

    
por 12.04.2016 / 07:00