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
5
  • 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. 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 Nov 8 '16 at 16:22
11

With fold + tac + tr :

$ echo 030201|fold -w2|tac|tr -d "\n"
010203
  • fold - split every 2 byte
  • tac - reverse cat
  • tr - remove newlines
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")
4
  • 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). 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
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.

8
  • 2
    I get 0102030a instead of 010203 Nov 8 '16 at 12:48
  • @l0b0 and too me,get 0102030a
    – Baba
    Nov 8 '16 at 12:49
  • 2
    @IñakiMurillo in your rev version 2.20.1; use this formate xxd -revert -plain <<< '030201' | LC_ALL=C rev | tr -d '\n'| xxd -plain
    – Baba
    Nov 8 '16 at 12:59
  • 2
    rev before version 2.24 have a new line bug . more info github.com/karelzak/util-linux/commit/…
    – Baba
    Nov 8 '16 at 13:33
  • 2
    It does not work if the hex string contains the '00' NUL byte. Nov 9 '16 at 8:43
5
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
  • 1
    This works if the '00' NUL byte is in the input. Nov 9 '16 at 8:54
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

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.