Se você deseja manter os utilitários de shell, pode usar head
para extrair um número de bytes e od
converter um byte em um número.
export LC_ALL=C # make sure we aren't in a multibyte locale
n=$(head -c 1 | od -An -t u1)
string=$(head -c $n)
No entanto, isso não funciona para dados binários. Existem dois problemas:
A substituição de comando $(…)
retira as novas linhas finais na saída do comando. Existe uma solução bastante fácil: verifique se a saída termina em um caractere diferente de uma nova linha e retire esse caractere.
string=$(head -c $n; echo .); string=${string%.}
Bash, como a maioria das conchas, é ruim em lidar com bytes nulos . A partir do bash 4.1, os bytes nulos são simplesmente eliminados do resultado da substituição do comando. O traço 0.5.5 e o pdksh 5.2 têm o mesmo comportamento, e o ATT ksh para de ler no primeiro byte nulo. Em geral, os shells e seus utilitários não são voltados para lidar com arquivos binários. (Zsh é a exceção, ele foi projetado para suportar bytes nulos.)
Se você possui dados binários, convém mudar para um idioma como Perl ou Python.
<input_file perl -e '
read STDIN, $c, 1 or die $!; # read length byte
$n = read STDIN, $s, ord($c); # read data
die $! if !defined $n;
die "Input file too short" if ($n != ord($c));
# Process $s here
'
<input_file python -c '
import sys
n = ord(sys.stdin.read(1)) # read length byte
s = sys.stdin.read(n) # read data
if len(s) < n: raise ValueError("input file too short")
# Process s here
'
Gilles 'SO- parar de ser mau'
fonte
fonte
read -N
pára em bytes nulos, portanto, essa não é uma maneira adequada de trabalhar com dados binários. Em geral, shells diferentes de zsh não conseguem lidar com nulos.Se você deseja lidar com arquivos binários no shell, a melhor opção (apenas?) É trabalhar com a ferramenta hexdump .
Somente leitura X bytes:
Leia o comprimento (e trabalhe com 0 como comprimento) e, em seguida, "string" como valor decimal em bytes:
fonte
UPDATE (com retrospectiva): ... Esta pergunta / resposta (minha resposta) me faz pensar no cachorro que continua perseguindo o carro .. Um dia, finalmente, ele alcança o carro .. Ok, ele pegou, mas ele realmente não pode fazer muito com isso ... Esse anser 'pega' as strings, mas você não pode fazer muito com elas, se elas tiverem bytes nulos incorporados ... (portanto, um grande +1 para Gilles responde .. outro idioma pode estar em ordem aqui.)
dd
lê todos e quaisquer dados ... Certamente, não será exibido em zero como um "comprimento" ... mas se você tiver \ x00 em qualquer lugar dos seus dados, precisará ser criativo ao lidar com eles;dd
não possui propblems, mas seu script shell terá problemas (mas depende do que você deseja fazer com os dados) ... O seguinte basicamente gera cada "string de dados" em um arquivo com um divisor de linha entre cada strin ...btw: Você diz "caractere" e suponho que você queira dizer "byte" ...
mas a palavra "caractere" tornou-se ambígua nos dias de UNICODE, onde apenas o conjunto de caracteres ASCII de 7 bits usa um único byte por caractere ... E mesmo no sistema Unicode, a contagem de bytes varia de acordo com o método de codificação de caracteres , por exemplo. UTF-8, UTF-16, etc.
Aqui está um script simples para destacar a diferença entre um "caractere" de texto e bytes.
Se o seu caractere de comprimento tiver 1 byte de comprimento e indicar um comprimento de byte , esse script deverá executar o truque, mesmo que os dados contenham caracteres Unicode ...
dd
só vê bytes independentemente de qualquer configuração de localidade ...Este script usa
dd
para ler o arquivo binário e gera as strings separadas por um divisor "====" ... Consulte o próximo script para obter dados de testeSaída
Este script cria dados de teste que incluem um prefixo de 3 bytes por linha ...
O prefixo é um único caractere Unicode codificado em UTF-8 ...
fonte
/dev/urandom
na maioria dos unices. E dados de teste aleatórios não são os melhores dados de teste, lembre-se de abordar casos difíceis, como, aqui, caracteres nulos e nova linha em locais de fronteira.Este apenas copia um arquivo binário:
fonte