bash não pode conter dados binários em suas variáveis. Já é ruim o suficiente processar texto com loops de shell, seria ainda pior para o processamento de dados binários. O shell é a ferramenta para executar outras ferramentas.
Observe também que o comando read buit-in lê caracteres, não bytes.
Além disso, dd faz uma read chamada de sistema, portanto, dd bs=77 count=1 não necessariamente lerá 77 bytes, especialmente se stdin for um canal (a implementação GNU de dd foi iflag=fullblock para isso).
Aqui, você deseja usar uma linguagem de programação de processamento de dados como perl :
Em perl :
perl -ne 'BEGIN{$/=}
print "Do something with the 77 byte long <$_> record\n"'
Com o GNU awk :
LC_ALL=C awk -vRS='.{,77}' '{print "the record is in <" RT ">"}'
Se você quiser usar um shell, sua melhor opção é provavelmente zsh , que é o único que pode armazenar dados binários em suas variáveis:
while LC_ALL=C IFS= read -ru0 -k77 record; do
print -r -- "you may only call builtins with $record
anyway since you can't pass NUL bytes in arguments
to an external command"
done
Se tudo o que você quer fazer é passar cada pedaço como stdin para uma nova invocação de some command , então você pode usar o GNU split e sua opção --filter :
split -b 77 --filter='some command'
--filter inicia um novo shell para avaliar some command para cada bloco. A menos que seu sh faça a otimização por si só, você pode fazer:
split -b 77 --filter='exec some command'
Para salvar um fork.
Usando dd , você poderia analisar sua saída stderr para descobrir o final da entrada. Você também precisaria do iflag=fullblock específico do GNU:
while
{
report=$({
LC_ALL=C dd bs=77 iflag=fullblock count=1 2>&3 |
some command >&4 3>&- 4>&-
} 3>&1)
} 4>&1
[ "${report%%+*}" -eq 1 ]
do
: nothing
done
Se o tamanho da entrada for múltiplo de 77, some command será executado um tempo extra com uma entrada vazia.