using bash: write bit representation of integer to file

18,371

Solution 1

You can use echo to emit specific bytes using hex or octal. For example:

echo -n -e \\x30 

will print ascii 0 (0x30)

(-n remove trailing newline)

Solution 2

printf is more portable than echo. This function takes a decimal integer and outputs a byte with that value:

echobyte () {
    if (( $1 >= 0 && $1 <= 255 ))
    then
        printf "\\x$(printf "%x" $1)"
    else
        printf "Invalid value\n" >&2
        return 1
    fi
}

$ echobyte 97
a
$ for i in {0..15}; do echobyte $i; done | hd
00000000  00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f  |................|
00000010

Solution 3

xxd is the better way. xxd -r infile outfile will take ascii hex-value in infile to patch outfile, and you can specify the specific position in infile by this: 1FE:55AA

Solution 4

I have a function to do this:

# number representation from 0 to 255 (one char long)
function chr() { printf "\\$(printf '%03o' "$1")" ; return 0 ; }
# from 0 to 65535 (two char long)
function word_litleendian() { chr $(($1 / 256)) ; chr $(($1 % 256)) ; return 0 ; }
function word_bigendian() { chr $(($1 % 256)) ; chr $(($1 / 256)) ; return 0 ; }
# from 0 to 4294967295 (four char long)
function dword_litleendian() { word_lilteendian $(($1 / 65536)) ; word_litleendian $(($1 % 65536)) ; return 0 ; }
function dword_bigendian() { word_bigendian $(($1 / 65536)) ; word_bigendian $(($1 % 65536)) ; return 0 ; }

You can use piping or redirection to catch the result.

Solution 5

Worked like a treat. I used the following code to replace 4 bytes at byte 24 in little endian with two integers (1032 and 1920). The code does not truncate the file.

echo -e \\x08\\x04\\x80\\x07 | dd of=<file> obs=1 oseek=24 conv=block,notrunc cbs=4

Thanks again.

Share:
18,371
Max Leske
Author by

Max Leske

Updated on June 05, 2022

Comments

  • Max Leske
    Max Leske almost 2 years

    I have a file with binary data and I need to replace a few bytes in a certain position. I've come up with the following to direct bash to the offset and show me that it found the place I want:

    dd bs=1 if=file iseek=24 conv=block cbs=2 | hexdump
    

    Now, to use "file" as the output:

    echo anInteger | dd bs=1 of=hextest.txt oseek=24 conv=block cbs=2
    

    This seems to work just fine, I can review the changes made in a hex editor. Problem is, "anInteger" will be written as the ASCII representation of that integer (which makes sense) but I need to write the binary representation.

    I want to use bash for this and the script should run on as many systems as possible (I don't know if the target system will have python or whatever installed).

    How do I tell the command to convert the input to binary (possibly from a hex)?

  • Max Leske
    Max Leske almost 14 years
    This seems to work. I'll try to figure it out and post my results.
  • Max Leske
    Max Leske almost 14 years
    I thought of that but I don't want to use an extra file for 4 bytes.
  • Max Leske
    Max Leske almost 14 years
    I tried it out. Your code will return a binary which will be written to the file as the ASCII representation of that binary. Nice thought though, thanks.
  • Max Leske
    Max Leske almost 14 years
    Sweet! But as you can see in my answer below, that would probably be overkill. Still, nice to know.
  • Gordon Davisson
    Gordon Davisson almost 14 years
    echo is disturbingly nonportable -- for the example above, some implementations will just print -e \x30, which isn't what you want at all.
  • Gordon Davisson
    Gordon Davisson almost 14 years
    If you know the integer(s) in advance, you can simplify this quite a bit, e.g. printf "\x30"
  • SourceSeeker
    SourceSeeker almost 14 years
    @Gordon: That's true see the OP's answer. However, the whole purpose of this function is versatility.
  • Max Leske
    Max Leske almost 14 years
    Weird, wouldn't have thought so. Luckily the script is already running without problems.
  • starfry
    starfry over 9 years
    why, oh why, isn't there a simple way to do this with decimal numbers? I'm converting to hex first - echo -ne \\x$(printf '%x' 65) surely there has to be a better way...?
  • Jérôme Pouiller
    Jérôme Pouiller almost 6 years
    I suggest to use printf instead of echo -n -e: printf \\x30
  • Maarten Bodewes
    Maarten Bodewes over 2 years
    Beware of the many problems with echo portability; it seems to be a serious thing. printf should be considered most of the time.
  • Max Leske
    Max Leske over 2 years
    Correct. This was already mentioned by @Dennis Williamson in a separate answer: stackoverflow.com/a/2747374/219324
  • MayeulC
    MayeulC over 2 years
    I would like to note that endianness conversion has been done manually in that answer.