Search code examples
bashhexendianness

Base16 and swap endianness in bash


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.


Solution

  • 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}"))