9

Is there a simple command to reverse an hexadecimal number?

For example, given the hexadecimal number:

030201

The output should be:

010203

Using the rev command, I get the following:

102030

Update

$ bash --version | head -n1
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
$ xxd -version
xxd V1.10 27oct98 by Juergen Weigert
$ rev --version
rev from util-linux 2.20.1
  • 2
    Please don't add the answer to your question. – cat Nov 8 '16 at 15:44
  • @cat I added the answer because the one that worked for me, is at the comments of the selected answer. But I'm ok removing it. – Iñaki Murillo Nov 8 '16 at 15:47
  • 2
    You could add it as an answer by clicking the "Answer this question" button below the answer box (self-answers are encouraged), and you should, just don't put it in the question. – cat Nov 8 '16 at 15:53
  • 2
    The C programmer in me wants to say "010203" is an octal number, not a hex number (0x10203) – infixed Nov 8 '16 at 16:18
  • @infixed You are not wrong, but I wanted an answer that treats 010203 as an hexadecimal, even though I do not use 0x – Iñaki Murillo Nov 8 '16 at 16:22
10

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.

10

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")
  • 3
    I was going to suggest perl -F'(..)' -lane 'print reverse(@F)' :) – Sundeep Nov 8 '16 at 12:59
  • 1
    @Sundeep, nice. I didn't know one could use -F like that. (I can see it described in the split() manual now). – Stéphane Chazelas Nov 8 '16 at 13:22
  • 1
    as far as I know, -F is basically splitting on $_.. apart from using regex like -F'/"\K\|(?=")/' one can specify number of splits as well... like -F'/:/,$_,2' ... use () if separator has to be captured as well – Sundeep Nov 8 '16 at 13:27
  • Instead of using paste you could use tr -d '\n' – AKHolland Nov 10 '16 at 21:35
9

With fold + tac + tr :

$ echo 030201|fold -w2|tac|tr -d "\n"
010203
  • fold - split every 2 byte
  • tac - reverse cat
  • tr - remove newlines
4
perl -nE 'say reverse /(..)/g'

This reverts each hexadecimal line:

  • /(..)/g buils a list with the captured matches
4

(for the sake of completeness)

$ echo 030201 | grep -o .. | tac | paste -sd '' -
010203
  • 1
    This works if the '00' NUL byte is in the input. – Sylvain Leroux Nov 9 '16 at 8:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.