11

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
cat
  • 3,428
  • 4
  • 22
  • 50
Iñaki Murillo
  • 745
  • 1
  • 4
  • 14
  • 2
    Please don't add the answer to your question. – cat Nov 08 '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 08 '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 08 '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 08 '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 08 '16 at 16:22

6 Answers6

12

With fold + tac + tr :

$ echo 030201|fold -w2|tac|tr -d "\n"
010203
  • fold - split every 2 byte
  • tac - reverse cat
  • tr - remove newlines
GAD3R
  • 63,407
  • 31
  • 131
  • 192
Ipor Sircer
  • 14,376
  • 1
  • 27
  • 34
11

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[])).

Or:

printf -v new_hex '%2$s%1$s' ${(s[]Oa)hex}

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")
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • 3
    I was going to suggest `perl -F'(..)' -lane 'print reverse(@F)'` :) – Sundeep Nov 08 '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 08 '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 08 '16 at 13:27
  • Instead of using paste you could use `tr -d '\n'` – AKHolland Nov 10 '16 at 21:35
8

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 00 (the NUL byte), because rev will truncate the output at that point, or 0a (newline), because rev reverses each line rather than the entire output.

l0b0
  • 50,672
  • 41
  • 197
  • 360
6
perl -nE 'say reverse /(..)/g'

This reverts each hexadecimal line:

  • /(..)/g buils a list with the captured matches
JJoao
  • 11,887
  • 1
  • 22
  • 44
4

(for the sake of completeness)

$ echo 030201 | grep -o .. | tac | paste -sd '' -
010203
zeppelin
  • 3,782
  • 10
  • 21
1

Based on Ipor Sircer's answer https://unix.stackexchange.com/a/321867/337458 I would recommend this in your ~/.bashrc to have a nice command that you simply can call:

function hex_inverse() {
    echo ${1} | fold -w2 | tac | tr -d "\n" ; echo "" 
}

$> hex_inverse 030201

010203
mschmoock
  • 111
  • 3