Base16 and swap endianness in bash

Viewed 215

I need to perform an operation in bash. I have this

401f

I like to perform these operations in bash:

  • swap endianness
  • from base16

In this way: https://gchq.github.io/CyberChef/#recipe=Swap_endianness('Hex',4,true)From_Base(16)&input=NDAxZg

So the result should be 8000. And I like to do it using the less dependencies as possible. I mean if that can be done using just linux core utils, then nice... I guess that something will be neede. Nnot sure what, maybe xxd, awk and that's ok, but I'd like to avoid the use of bc and stuff like that. Thanks.

1 Answers

Easy to do in shell using arithmetic expansion, which supports bitwise operations.

num=401f
# Add a 0x prefix so it's treated as base 16 in shell arithmetic.
num="0x$num"
# Swap the bytes in a 16-bit number and print the result in base 10
printf "%d\n" $(( ((num & 0xFF) << 8) | (num >> 8) ))
# Or assign to a variable, etc.
newnum=$(( ((num & 0xFF) << 8) | (num >> 8) ))

Handy bash functions for 16-bit and 32-bit byte swaps:

bswap16() {
    # Default to 0 if no argument given
    local num="0x${1:-0}"
    printf "%d\n" $(( ((num & 0xFF) << 8) | (num >> 8) ))
}

bswap32() {
    local num="0x${1:-0}"
    printf "%d\n" $(( ((num & 0xFF) << 24) |
                      (((num >>  8) & 0xFF) << 16) |
                      (((num >> 16) & 0xFF) <<  8) |
                        (num >> 24) ))
}

bswap16 401f # 8000
bswap32 401f # 524288000

An alternative using bash's parameter substring expansion (Unlike the above, this version requires that the number have 4 hex digits to work right):

num=401f
echo $(("0x${num:2:2}${num:0:2}"))
Related