como ler uma string terminada em nul em um arquivo binário

1

Eu tenho um arquivo binário que é preenchido com valores de FF . Eu preenchi seu início com muitos printf000 . Em seguida, iniciei seu início com 10 printf MY_STR=${eeprom:OFFSET}0eeprom0MY_STR=${eeprom:OFFSET:LENGTH}00FF0sh0input0xxd -c 1 input0s.sh0%code%0%code%0MAC_ADDRESS=12:34:56:78:90,PCB_MAIN_ID=m/SF-1V/MAIN/0.0,PCB_PIGGY1_ID=n/SF-1V/PS/0.0,CSL_HW_VARIANT=D%code%0' > eeprom , para obter algum tipo de deslocamento e, em seguida, escrevi uma sequência mais curta, também terminada com %code%

Eu usei este %code% :

%code%

É assim que aparece quando mostro o hexdump do arquivo

Agora,oqueeuquerosaberécomopossolerastring.Eupossousar%code%(%code%éonomedoarquivo)quemedaráastring,mastambémmedaráorestodoarquivoqueeunãoquero.Comopossopará-loquandoencontrapelaprimeiravez%code%?

  • Nãoépossívelusar%code%porqueotamanhodastringédesconhecido
  • Outracoisa-comopossopreenchê-lonovamentecom%code%?
  • Usando%code%(busybox)

EDITAR

Tentandofazerumpequenoexemplodisso...Eutenhoumarquivo%code%comessesvalores(após%code%):

0000000:68h0000001:65e0000002:6cl0000003:6cl0000004:6fo0000005:2c,0000006:200000007:00.0000008:69i0000009:74t000000a:27'000000b:73s000000c:20000000d:6dm000000e:65e000000f:2c,0000010:00.

eeutenhoessescript%code%:

BUF=""
for c in $(xxd -p input); do
    if [ "${c}" != 00 ]; then
        BUF="$BUFc";
    else
        break;
    fi
done

echo $BUF

e eu esperava que ele ecoasse "olá", no entanto, nada é impresso

    
por CIsForCookies 16.05.2018 / 15:40

1 resposta

1

Solução 1: atribuição de variável direta

Se tudo o que você está preocupado são os bytes nulos, então você deve ser capaz de ler diretamente os dados do arquivo em uma variável usando qualquer método padrão que preferir, ou seja, você deve ser capaz de simplesmente ignorar os bytes nulos e leia os dados do arquivo. Aqui está um exemplo usando o comando cat e a substituição de comandos:

$ data="$(cat eeprom)"
$ echo "${data}"
MAC_ADDRESS=12:34:56:78:90,PCB_MAIN_ID=m/SF-1V/MAIN/0.0,PCB_PIGGY1_ID=n/SF-1V/PS/0.0,CSL_HW_VARIANT=D

Isso funcionou para mim dentro de um contêiner do Docker do BusyBox.

Solução 2: usando xxd e for loop

Se você quiser mais controle do que você pode usar xxd para converter os bytes em seqüências de caracteres hexadecimais e iterar sobre essas seqüências de caracteres. Em seguida, ao interagir com essa string, você poderá aplicar a lógica que desejar, por exemplo, você poderia ignorar explicitamente os valores nulos iniciais e imprimir o restante dos dados até atingir alguma condição de quebra.

Aqui está um script que especifica uma "lista branca" de caracteres válidos (ASCII 32 a 127), trata qualquer subsequência de outros caracteres como um separador e extrai todas as subseqüências válidas:

#!/bin/sh
# get_hex_substrings.sh

# Get the path to the data-file as a command-line argument
datafile="$1"

# Keep track of state using environment variables
inside_padding_block="true"
inside_bad_block="false"

# NOTE: The '-p' flag is for "plain" output (no additional formatting)
# and the '-c 1' option specifies that the representation of each byte
# will be printed on a separate line
for h in $(xxd -p -c 1 "${datafile}"); do

    # Convert the hex character to standard decimal
    d="$((0x${h}))"

    # Case where we're still inside the initial padding block
    if [ "${inside_padding_block}" == "true" ]; then
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            inside_padding_block="false";
            printf '\x'"${h}";
        fi

    # Case where we're passed the initial padding, but inside another
    # block of non-printable characters
    elif [ "${inside_bad_block}" == "true" ]; then
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            inside_bad_block="false";
            printf '\x'"${h}";
        fi

    # Case where we're inside of a substring that we want to extract
    else
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            printf '\x'"${h}";
        else
            inside_bad_block="true";
            echo
        fi
    fi
done

if [ "${inside_bad_block}" == "false" ]; then
    echo
fi

Agora podemos testar isso criando um arquivo de exemplo que tenha \x00 e \xff subsequences separando substrings:

printf '\x00\x00\x00string1\xff\xff\xffstring2\x00\x00\x00string3\x00\x00\x00' > data.hex

E aqui está a saída que obtemos ao executar o script:

$ sh get_hex_substrings.sh data.hex
string1
string2
string3

Solução 3: usando os comandos tr e cut

Você também pode tentar usar os comandos tr e cut para lidar com os bytes nulos. Aqui está um exemplo de extrair a primeira string terminada em nulo de uma lista de strings terminadas em nulo, comprimindo / colando caracteres nulos adjacentes e convertendo-os em novas linhas:

$ printf '
$ data="$(cat eeprom)"
$ echo "${data}"
MAC_ADDRESS=12:34:56:78:90,PCB_MAIN_ID=m/SF-1V/MAIN/0.0,PCB_PIGGY1_ID=n/SF-1V/PS/0.0,CSL_HW_VARIANT=D
0
#!/bin/sh
# get_hex_substrings.sh

# Get the path to the data-file as a command-line argument
datafile="$1"

# Keep track of state using environment variables
inside_padding_block="true"
inside_bad_block="false"

# NOTE: The '-p' flag is for "plain" output (no additional formatting)
# and the '-c 1' option specifies that the representation of each byte
# will be printed on a separate line
for h in $(xxd -p -c 1 "${datafile}"); do

    # Convert the hex character to standard decimal
    d="$((0x${h}))"

    # Case where we're still inside the initial padding block
    if [ "${inside_padding_block}" == "true" ]; then
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            inside_padding_block="false";
            printf '\x'"${h}";
        fi

    # Case where we're passed the initial padding, but inside another
    # block of non-printable characters
    elif [ "${inside_bad_block}" == "true" ]; then
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            inside_bad_block="false";
            printf '\x'"${h}";
        fi

    # Case where we're inside of a substring that we want to extract
    else
        if [ "${d}" -ge 32 ] && [ "${d}" -le 127 ]; then
            printf '\x'"${h}";
        else
            inside_bad_block="true";
            echo
        fi
    fi
done

if [ "${inside_bad_block}" == "false" ]; then
    echo
fi
0
printf '\x00\x00\x00string1\xff\xff\xffstring2\x00\x00\x00string3\x00\x00\x00' > data.hex
0string1
$ sh get_hex_substrings.sh data.hex
string1
string2
string3
0
$ printf '%pre%0%pre%0%pre%0string1%pre%0%pre%0%pre%0string2%pre%0%pre%0%pre%0string3%pre%0%pre%0%pre%0' > file.dat
$ tr -s '%pre%0' '\n' < file.dat | cut -d$'\n' -f2
string1
0%pre%0string2%pre%0%pre%0%pre%0string3%pre%0%pre%0%pre%0' > file.dat $ tr -s '%pre%0' '\n' < file.dat | cut -d$'\n' -f2 string1
    
por 16.05.2018 / 16:02