Reverse a hexadecimal number in bash

You can convert it to binary, reverse the bytes, optionally remove trailing newlines rev <2.24, and convert it back:

$ xxd -revert -plain <<< 030201 | LC_ALL=C rev | tr -d '\n' | xxd -plain
010203

Using

$ bash --version | head -n1
GNU bash, version 4.3.42(1)-release (x86_64-redhat-linux-gnu)
$ xxd -version
xxd V1.10 27oct98 by Juergen Weigert
$ rev --version
rev from util-linux 2.28.2

This does not work if the string contains the NUL byte, because rev will truncate the output at that point.


If your system has a rev command.

hex=030201
new_hex=$(printf %s "$hex" | dd conv=swab 2> /dev/null | rev)

If it has a tac or tail -r command:

new_hex=$(echo "$hex" | fold -w 2 | tac | paste -sd '\0' -)

With zsh:

setopt extendedglob
new_hex=${(j::)${(s::Oa)${hex//(#b)(?)(?)/$match[2]$match[1]}}}

(like in the dd approach: swap pairs of characters, split into list of individual characters (s::), reverse the order (Oa) and join (j::)).

POSIXly:

new_hex=$(
  awk '
    BEGIN {
      hex = ARGV[1]; l = length(hex)
      for (i = 1; i < l; i += 2)
        new_hex = substr(hex, i, 2) new_hex
      print new_hex
    }' "$hex"
)

Or

new_hex=$(echo "$hex" |
  sed -e 'G;:1' -e 's/\(..\)\(.*\n\)/\2\1/;t1' -e 's/.//')

With perl:

new_hex=$(perl -le 'print reverse(shift =~ /../g)' -- "$hex")

With fold + tac + tr :

$ echo 030201|fold -w2|tac|tr -d "\n"
010203
  • fold - split every 2 byte
  • tac - reverse cat
  • tr - remove newlines