How to convert hex to ASCII characters in the Linux shell?

LinuxBashShellEncodingScripting

Linux Problem Overview


Lets say that I have a string 5a.

This is the hex representation of the ASCII letter Z.

I need to know a Linux shell command which will take a hex string and output the ASCII characters that the string represents.

So if I do:

echo 5a | command_im_looking_for

I will see a solitary letter Z:

Z

Linux Solutions


Solution 1 - Linux

I used to do this with xxd:

echo -n 5a | xxd -r -p

But then I realised that in Debian/Ubuntu, xxd is part of vim-common and hence might not be present in a minimal system. To also avoid Perl (IMHO also not part of a minimal system), I ended up using sed, xargs, and printf like this:

echo -n 5a | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf

Mostly, I only want to convert a few bytes and it's okay for such tasks. The advantage of this solution over the one of ghostdog74 is, that this can convert hex strings of arbitrary lengths automatically. xargs is used because printf doesnt read from standard input.

Solution 2 - Linux

echo -n 5a | perl -pe 's/([0-9a-f]{2})/chr hex $1/gie'

Note that this won't skip non-hex characters. If you want just the hex (no whitespace from the original string etc):

echo 5a | perl -ne 's/([0-9a-f]{2})/print chr hex $1/gie'

Also, zsh and bash support this natively in echo:

echo -e '\x5a'

Solution 3 - Linux

You can do this with echo only, without the other stuff. Don't forget to add "-n" or you will get a linebreak automatically:

echo -n -e "\x5a"

Solution 4 - Linux

Bash one-liner

echo -n "5a" | while read -N2 code; do printf "\x$code"; done

Solution 5 - Linux

Some Python 3 one-liners that work with any number of bytes.

Decoding hex

Using strip, so that it's ok to have a newline on stdin.

$ echo 666f6f0a | python3 -c "import sys, binascii; sys.stdout.buffer.write(binascii.unhexlify(input().strip()))"
foo

Encoding hex

$ echo foo | python3 -c "import sys, binascii; print(binascii.hexlify(sys.stdin.buffer.read()).decode())"
666f6f0a

Solution 6 - Linux

Depending on where you got that "5a", you can just prepend "\x" to it and pass that to printf:

$ a=5a
$ a="\x${a}"
$ printf "$a"
Z

Solution 7 - Linux

echo 5a | python -c "import sys; print chr(int(sys.stdin.read(),base=16))"

Solution 8 - Linux

Here is a pure bash script (as printf is a bash builtin) :

#warning : spaces do matter
die(){ echo "$@" >&2;exit 1;}

p=48656c6c6f0a

test $((${#p} & 1)) == 0 || die "length is odd"
p2=''; for ((i=0; i<${#p}; i+=2));do p2=$p2\\x${p:$i:2};done
printf "$p2"

If bash is already running, this should be faster than any other solution which is launching a new process.

Solution 9 - Linux

dc can convert between numeric bases:

$ echo 5a | (echo 16i; tr 'a-z' 'A-Z'; echo P) | dc
Z$

Solution 10 - Linux

There is a simple shell command ascii.

If you use Ubuntu, install it with:

sudo apt install ascii

Then

ascii 0x5a

will output:

ASCII 5/10 is decimal 090, hex 5a, octal 132, bits 01011010: prints as `Z'
Official name: Majuscule Z
Other names: Capital Z, Uppercase Z

Solution 11 - Linux

As per @Randal comment, you can use perl, e.g.

$ printf 5a5a5a5a | perl -lne 'print pack "H*", $_'
ZZZZ

and other way round:

$ printf ZZZZ | perl -lne 'print unpack "H*", $_'
5a5a5a5a

Another example with file:

$ printf 5a5a5a5a | perl -lne 'print pack "H*", $_' > file.bin
$ perl -lne 'print unpack "H*", $_' < file.bin
5a5a5a5a

Solution 12 - Linux

You can use this command (python script) for larger inputs:

echo 58595a | python -c "import sys; import binascii; print(binascii.unhexlify(sys.stdin.read().strip()).decode())"

The result will be:

XYZ

And for more simplicity, define an alias:

alias hexdecoder='python -c "import sys; import binascii; print(binascii.unhexlify(sys.stdin.read().strip()).decode())"'

echo 58595a | hexdecoder

Solution 13 - Linux

GNU awk 4.1

awk -niord '$0=chr("0x"RT)' RS=.. ORS=

Note that if you echo to this it will produce an extra null byte

$ echo 595a | awk -niord '$0=chr("0x"RT)' RS=.. ORS= | od -tx1c
0000000  59  5a  00
          Y   Z  \0

Instead use printf

$ printf 595a | awk -niord '$0=chr("0x"RT)' RS=.. ORS= | od -tx1c
0000000  59  5a
          Y   Z

Also note that GNU awk produces UTF-8 by default

$ printf a1 | awk -niord '$0=chr("0x"RT)' RS=.. ORS= | od -tx1
0000000 c2 a1

If you are dealing with characters outside of ASCII, and you are going to be Base64 encoding the resultant string, you can disable UTF-8 with -b

echo 5a | sha256sum | awk -bniord 'RT~/\w/,$0=chr("0x"RT)' RS=.. ORS=

Solution 14 - Linux

Similar to my answer here: https://stackoverflow.com/questions/9605927/linux-shell-scripting-hex-number-to-binary-string/47253189#47253189

You can do it with the same tool like this (using ascii printable character instead of 5a):

echo -n 616263 | cryptocli dd -decoders hex

Will produce the following result:

abcd

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKrystian CybulskiView Question on Stackoverflow
Solution 1 - LinuxjoschView Answer on Stackoverflow
Solution 2 - LinuxbdonlanView Answer on Stackoverflow
Solution 3 - LinuxFa11enAngelView Answer on Stackoverflow
Solution 4 - Linuxuser3132194View Answer on Stackoverflow
Solution 5 - LinuxJack O'ConnorView Answer on Stackoverflow
Solution 6 - Linuxghostdog74View Answer on Stackoverflow
Solution 7 - LinuxunutbuView Answer on Stackoverflow
Solution 8 - LinuxVouzeView Answer on Stackoverflow
Solution 9 - LinuxRoger WillcocksView Answer on Stackoverflow
Solution 10 - LinuxYingchunView Answer on Stackoverflow
Solution 11 - LinuxkenorbView Answer on Stackoverflow
Solution 12 - LinuxMahdi PerfectView Answer on Stackoverflow
Solution 13 - LinuxZomboView Answer on Stackoverflow
Solution 14 - LinuxtehmoonView Answer on Stackoverflow