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.