Geralmente é esperado que os shells sejam lentos no processamento de grandes pedaços de dados. Para a maioria dos scripts, você sabe antecipadamente quais bits de dados provavelmente serão pequenos e quais bits de dados provavelmente serão grandes.
- Prefere confiar nos built-ins do shell para dados pequenos, porque o processo de forking e execução de um processo externo induz uma sobrecarga constante.
- Prefere confiar em ferramentas externas de propósito específico para dados grandes, porque as ferramentas compiladas para fins especiais são mais eficientes do que uma linguagem de propósito geral interpretada.
dd
faz as chamadas read
e write
que usam o tamanho do bloco. Você pode observar isso com strace (ou truss, trace,… dependendo do seu sistema operacional):
$ strace -s9 dd if=/dev/zero of=/dev/null ibs=1024k obs=2048k count=4
✄
read(0, "$ strace -s9 dd if=/dev/zero of=/dev/null ibs=1024k obs=2048k count=4
✄
read(0, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
read(0, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
write(1, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 2097152) = 2097152
read(0, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
read(0, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
write(1, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 2097152) = 2097152
✄
%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
read(0, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
write(1, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 2097152) = 2097152
read(0, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
read(0, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 1048576) = 1048576
write(1, "%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%"..., 2097152) = 2097152
✄
A maioria das outras ferramentas tem um limite muito menor no tamanho máximo do buffer, portanto, elas criariam mais syscalls e, portanto, levariam mais tempo. Mas note que este é um benchmark irreal: se você estivesse escrevendo para um arquivo regular ou um pipe ou um socket, o kernel provavelmente não escreveria mais do que alguns kilobytes por syscall de qualquer maneira.