Buscando bytes individuais de um arquivo binário em uma variável com o bash

4

Eu preciso criar um script bash bastante simples para extrair bytes um de cada vez de um arquivo binário, enviá-lo por uma porta serial e esperar que um byte retorne antes de eu enviar o próximo. Isso é efetivamente para um programador de EEPROM, onde uma solução pronta não funcionará.

Estou principalmente preso a puxar os bytes para fora do arquivo em uma variável, além disso eu sei que posso ecoar os valores pela porta serial e lê-los de volta com o dd. (Existe uma maneira melhor de fazer isso também?)

Obrigado pela ajuda!

    
por Minifig666 11.09.2014 / 19:17

4 respostas

3

Use dd ou xxd (parte do Vim), por exemplo, para ler um byte ( -l ) no deslocamento 100 ( -s ) do arquivo binário try:

xxd -p -l1 -s 100 file.bin

para usar deslocamentos hexadecimais, no Bash você pode usar essa sintaxe $((16#64)) , por exemplo:

echo $((16#$(xxd -p -l1 -s $((16#FC)) file.bin)))

que lê byte no deslocamento FC e imprime em formato decimal.

Como alternativa, use dd , como:

dd if=file.bin seek=$((16#FC)) bs=1 count=5 status=none

que fará o dump dos dados brutos de 5 bytes no deslocamento hexadecimal FC .

Depois, você pode atribuí-lo à variável, mas não funcionará quando seus dados tiverem bytes nulos , portanto, você pode pulá-los ( xxd -a ) ou como solução alternativa você pode armazená-los em formato hexadecimal simples.

Por exemplo:

  1. Leia 10 bytes no deslocamento 10 na variável que contém bytes no formato hexadecimal:

    hex=$(xxd -p -l 10 -s 10 file.bin)
    
  2. Em seguida, escreva-os em arquivo ou dispositivo:

    xxd -r -p > out.bin <<<$hex
    

Aqui estão algumas funções úteis no Bash:

set -e

# Read single decimal value at given offset from the file.
read_value() {
  file="$1"
  offset="$2"
  [ -n "$file" ]
  [ -n "$offset" ]
  echo $((16#$(xxd -p -l1 -s $offset "$file")))
}

# Read bytes in hex format at given offset from the file.
read_data() {
  file="$1"
  offset="$2"
  count="$3:-1"
  xxd -p -l $count -s $offset "$file"
}

Uso da amostra:

read_value file.bin $((16#FC)) # Read 0xFC offset from file.bin.
    
por 20.02.2016 / 23:20
2

Não tenho certeza se entendi a visão geral do que você está pedindo, mas tenho algumas abordagens que você pode querer considerar:

Use dd para ler seu arquivo de entrada

exec 3 < input_file
while true
do
    dd bs=1 count=1 <&3 > this_byte
    if ! [ -s this_byte ]       # If size is zero, we’re done.
    then
        break
    fi
    code using the this_byte file
          ︙
done

Use od para digerir seu arquivo de entrada

od -bv input_file | while read a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16
do                              # Skip $a0; it’s the address.
    for byte_val in "$a1" "$a2" "$a3" "$a4" "$a5" "$a6" "$a7" "$a8" "$a9" "$a10" \
                                "$a11" "$a12" "$a13" "$a14" "$a15" "$a16"
    do
        if [ "$byte_val" = "" ]
        then
            break
        fi
        code using the $byte_val value
        for example: echo -e "
exec 3 < input_file
while true
do
    dd bs=1 count=1 <&3 > this_byte
    if ! [ -s this_byte ]       # If size is zero, we’re done.
    then
        break
    fi
    code using the this_byte file
          ︙
done
$byte_val\c" ︙ done done
    
por 11.09.2014 / 23:28
1

Isto é provavelmente mais fácil de fazer com um programa C minúsculo, ou um (quase) one-liner em uma linguagem de script como Python ou Perl.

O shell Unix é um interpretador para comandos de usuário , que (por conveniência na escrita de comandos repetitivos) tem recursos rudimentares para programação. Muitas vezes ele é (mal) usado porque uma versão do shell Bourne está garantida para estar disponível em qualquer sistema Unix, não porque é uma linguagem de programação particularmente boa (ou até mesmo meio decente). / p>     

por 20.02.2016 / 23:49
0

Você pode usar perl :

$ printf '%s%s%s' 'ăâé' | LC_ALL=C.UTF-8 perl -Mopen=locale -ne '
    BEGIN { $/ =  }
    printf "%s\n", $_;
'
ă
â
é
    
por 11.09.2014 / 19:59