Solution 1: Direct Variable Assignment
If all you're worried about are the null bytes then you should just be able to directly read the data from the file into a variable using whichever standard method you prefer, i.e. you should be able to just ignore the null bytes and read the data from the file. Here's an example using the cat
command and command substitution:
$ 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
This worked for me inside of a BusyBox Docker container.
Solution 2: Using xxd
and a for
loop
If you want more control than you can use xxd
to convert the bytes to hexadecimal strings and iterate over these strings. Then, while iterating over these string, you can apply whatever logic you'd like, e.g. you could explicitly skip over the initial null values and print the rest of the data until you reach some break condition.
Here's a script that specifies a "white-list" of valid characters (ASCII 32 through 127), treats any subsequence of other characters as a separator, and extracts all valid substrings:
#!/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
Now we can test this out by creating an example file which has both \x00
and \xff
subsequences separating substrings:
printf '\x00\x00\x00string1\xff\xff\xffstring2\x00\x00\x00string3\x00\x00\x00' > data.hex
And here's the output we get when running the script:
$ sh get_hex_substrings.sh data.hex
string1
string2
string3
Solution 3: Using the tr
and cut
commands
You could also try using the tr
and cut
commands to deal with the null bytes. Here's an example of extracting the first null-terminated string from a list of null-terminated strings by squeezing/collapsing adjacent null-characters and converting them to newlines:
$ printf '\000\000\000string1\000\000\000string2\000\000\000string3\000\000\000' > file.dat
$ tr -s '\000' '\n' < file.dat | cut -d$'\n' -f2
string1
sh
doesn't sound like something that would work well with NUL-separated data. Zsh or even Bash would better. Or some actual programming language, like Perl. Are there any other tools than busybox you can use?strings
will extract null terminated strings from binary files