Estou colocando minha própria resposta. Pode não ser o melhor, mas está tudo bem.
Cuidado
Isso está escrito na frente depois de muitos testes.
Não encadeie DDs demais para armazenar em buffer, ou todos os seus núcleos de CPU podem bloquear o IO, e seu computador irá congelar mesmo se você tiver toneladas de memória sobrando!
Especialmente tóxico se você tiver uma unidade USB externa lenta e quebrada que também precise de uma intensidade ridícula de IO para ler / escrever.
Exemplos
Eu basicamente esgotou todas as combinações de opções de DD. Um único DD parece ser impossível para essa tarefa, já que não pode executar IO assíncrono. Caso contrário, na cadeia de buffer DD, o maior bloco deve ser preenchido antes de começar a agir como um FIFO. Então, se você não se importa com o atraso inicial ao encher o tubo ... Uma cadeia de trabalho de dois dds. Espero que alguém possa fornecer uma solução mais elegante, mas aqui está um exemplo de uso.
Exemplo 1 : Tarring todos os arquivos de um HDD A muito fragmentado (tremores de tempo de resposta) para um HDD B altamente fragmentado (jitters), usando XZ como algoritmo de compressão (lento) em paralelo você está realmente usando o computador) (disclaimer: Estou escrevendo isso da minha cabeça, então pequenos detalhes podem estar errados. Use a seu próprio risco):
tar -cpSf - -C /mnt/A . | \
dd obs=1024M | dd obs=1024M | \
xz -T 0 -c | \
dd obs=1024M | dd obs=1024M | \
dd bs=512M iflag=fullblock of=/mnt/B/A.tar.xz
Adicione pv
para ver a velocidade. Aqui, xz
é iniciado somente depois que os dados de 1 GB são lidos de A (a menos que tenha menos de 1 GB, ele será concluído). Da mesma forma, a gravação em disco para B começa somente após os dados de 1 GB saírem do xz. Esse código fornece um buffer de 2 GB entre tar
e xz
e 2 GB entre xz
e gravação. O bs=512M
no final não é realmente necessário, mas descobri que um tamanho de bloco grande (> 64M) oferece uma velocidade de gravação média melhor, especialmente em discos rígidos USB. Eu suponho que ele cria menos fragmentos também, se a unidade B estiver em uso (não confirmada).
Exemplo 2 . Objetivo: copiar um arquivo gigantesco de um disco strongmente fragmentado A para um disco muito fragmentado B.
dd if=/mnt/A/file obs=<half of cache you want> | dd bs=<half of cache> iflag=fullblock oflag=direct of=/mnt/B/file
Esta é uma das formas mais simples que posso encontrar. Se o arquivo for gigantesco o suficiente, o tempo inicial usado para preencher o cache deve ser insignificante. Enquanto isso, lê / escreve de forma assíncrona, e espera-se que grupos escrevam o suficiente para obter algum desempenho sequencial. Suponho que o SSD não se importe com o tamanho do bloco, no entanto.
Exemplo 3 . Graças a Kamil Maciorowski, agora tenho o seguinte no meu .zshrc
:
buffer() {
if [ "$2" -gt 0 ] ; then
dd status=none obs="$1" | buffer "$1" $(($2-1))
else
cat
fi
}
Agora, se você precisar de 3 blocos de buffer de 512M, encadeie buffer 512M 3
em seu pipeline. Geralmente, se o seu trabalho é grande o suficiente para o seu rendimento (por exemplo, Copiando / Comprimindo 100GB + dados @ 100MB / s em média), um bloco menor não dá vantagem além de preencher o tubo mais rapidamente (o que é irrelevante já que esse tempo é pequeno) . Eu observei que, se você colocar muitos blocos, a CPU pode estar tão ocupada com o IO que o comando congela o computador inteiro.
Agora, o Exemplo 1 se torna
tar -cpSf - -C /mnt/A . | \
buffer 1024M 2 | \
xz -T 0 -c | \
buffer 1024M 2 | \
dd bs=512M iflag=fullblock of=/mnt/B/A/tar.xz