69

I'm now doing it this way:

[root@~]# echo Aa|hexdump -v 0000000 6141 000a 0000003 [root@~]# echo -e "\x41\x41\x41\x41" AAAA 

But it's not exactly behaving as I wanted,

the hex form of Aa should be 4161,but the output is 6141 000a,which seems not making sense.

and when performing hex to ascii,is there another utility so that I don't need the prefix \x ?

2

17 Answers 17

77

The reason is because hexdump by default prints out 16-bit integers, not bytes. If your system has them, hd (or hexdump -C) or xxd will provide less surprising outputs - if not, od -t x1 is a POSIX-standard way to get byte-by-byte hex output. You can use od -t x1c to show both the byte hex values and the corresponding letters.

If you have xxd (which ships with vim), you can use xxd -r to convert back from hex (from the same format xxd produces). If you just have plain hex (just the '4161', which is produced by xxd -p) you can use xxd -r -p to convert back.

Sign up to request clarification or add additional context in comments.

4 Comments

xxd -p -r AAA,this doesn't work,can it retrieve parameters from command line directly?
no... and the 'r' converts back from hex, you'd want something like 'echo 4161 | xxd -r -p' or 'echo Aa | xxd -p'
Just FYI xxd is broken as of now. It desplays all zeroes instead of data. Maybe specific to my setup (xxd 2021-10-22, Ubuntu 22.04, large files > 2Gb), but anyway you should be aware of that (I lost some time to figure out what's going on).
@midenok If your data is displaying all zeroes, then your data has been zeroed i.e. wiped. I can't see any way that xxd would add zero hex data to a file that wasn't already zeroed.
33

For the first part, try

echo Aa | od -t x1 

It prints byte-by-byte

$ echo Aa | od -t x1 0000000 41 61 0a 0000003 

The 0a is the implicit newline that echo produces.

Use echo -n or printf instead.

$ printf Aa | od -t x1 0000000 41 61 0000002 

2 Comments

How to convert hex back to ascii?
example: echo -e "\x68"
27
$> printf "%x%x\n" "'A" "'a" 4161 

3 Comments

@gdb: See printf where it says: "If the leading character is a single-quote or double-quote, the value shall be the numeric value in the underlying codeset of the character following the single-quote or double-quote."
The c-style printf solution here should be the accepted answer. It is the most portable and the most simple, and keeps with POSIX compliance without needing external tools that may or may not be available.
How is this not the top answer? Its the only solution here which uses a single "BASh built-in" (rather than multiple pipe redirects)
24

For single line solution:

echo "Hello World" | xxd -ps -c 200 | tr -d '\n' 

It will print:

48656c6c6f20576f726c640a 

or for files:

cat /path/to/file | xxd -ps -c 200 | tr -d '\n' 

For reverse operation:

echo '48656c6c6f20576f726c640a' | xxd -ps -r 

It will print:

Hello World 

Comments

4

With bash :

a=abcdefghij for ((i=0;i<${#a};i++));do printf %02X \'${a:$i:1};done 

6162636465666768696A

1 Comment

wrong output for some characters like (space, tab, \r,\n) all of these characters will be shown as \x00
4

I use:

> echo Aa | tr -d '\n' | xxd -p 4161 > echo 414161 | tr -d '\n' | xxd -r -p AAa 

The tr -d '\n' will trim any possible newlines in your input

2 Comments

On macOS you can also use echo -n Aa instead of echo Aa | tr -d '\n'.
@p13rr0m You are right, It should also work on all *nix systems.
2

I don't know how it crazy it looks but it does the job really well

ascii2hex(){ a="$@";s=0000000;printf "$a" | hexdump | grep "^$s"| sed s/' '//g| sed s/^$s//;} 

Created this when I was trying to see my name in HEX ;) use how can you use it :)

Comments

2
Text2Conv="Aa" for letter in $(echo "$Text2Conv" | sed "s/\(.\)/'\1 /g");do printf '%x' "$letter";done 

4161

The trick is using sed to parse the Text2Conv to format we can then seperate anf loop using for.

Comments

2

Finally got the correct thing

echo "Hello, world!" | tr -d '\n' | xxd -ps -c 200 

2 Comments

echo -n "Hello, world!" | xxd -ps -c 200 would also work
I typically use xxd -ps -c 200 <<< "Hello, world!"
1

here a little script I wrote to convert ascii to hex. hope it helps:

echo '0x'"`echo 'ASCII INPUT GOES HERE' | hexdump -vC | awk 'BEGIN {IFS="\t"} {$1=""; print }' | awk '{sub(/\|.*/,"")}1' | tr -d '\n' | tr -d ' '`" | rev | cut -c 3- | rev 

Comments

1

SteinAir's answer above was helpful to me -- thank you! And below is a way it inspired, to convert hex strings to ascii:

for h in $(echo "4161" | sed "s/\(..\)/\1 /g"); do printf `echo "\x$h"`;done Aa 

Comments

1
echo -n Aa | hexdump -e '/1 "%02x"'; echo 

Comments

1

Pure bash, without loop Ascii <-> Hex convertion

1. Ascii to Hexadecimal conversion in bash

Very quick and short:

string='Hello World.' oIFS="$IFS" IFS=$'\n' printf '%02X\n' ${string//?/$'\n'\'&}; IFS="$oIFS" 

Will produce:

48 65 6C 6C 6F 20 57 6F 72 6C 64 2E 

Yes, in order to handle space, we have to play with $IFS.

1.1. Into an variable of type array:

string='Hello World.' oIFS="$IFS" IFS=$'\n' printf -v string '%02X\n' ${string//?/$'\n'\'&}; IFS="$oIFS" mapfile -t array <<<${string%$'\n'} echo ${array[@]@Q} 
'48' '65' '6C' '6C' '6F' '20' '57' '6F' '72' '6C' '64' '2E' 

1.2. Better into a function to populate an array:

In a function, we could localize $IFS, things become a little simplier.

ascii2hex() { local _varname=$1 _string=${*:2} IFS=$'\n' printf -v _string '%02X\n' ${_string//?/$'\n'\'&} mapfile -t "$_varname" <<<${_string%$'\n'} } ascii2hex myArray 'Hello world!' echo ${myArray[@]@Q} 
'48' '65' '6C' '6C' '6F' '20' '77' '6F' '72' '6C' '64' '21' 

Note: as function use ${*:2} as source string, space don't need to be quoted:

ascii2hex myArray Hello world! echo ${myArray[@]@Q} 
'48' '65' '6C' '6C' '6F' '20' '77' '6F' '72' '6C' '64' '21' 

2. Hexadecimal to Ascii conversion in bash

Simply:

printf '%b' ${myArray[@]/#/\\x} 
Hello world! 

2.1. Then into a variable:

printf -v string '%b' ${myArray[@]/#/\\x} echo $string 
Hello world! 

2.2. Into a function to define a variable

hex2ascii() { local _array=(${*:2}) printf -v "$1" '%b' ${_array[@]/#/\\x} } hex2ascii mystring ${myArray[@]} echo "$mystring" 
Hello world! 

Comments

0

according to http://mylinuxbook.com/hexdump/ you might use the hexdump format parameter

echo Aa | hexdump -C -e '/1 "%02X"' 

will return 4161

to add an extra linefeed at the end, append another formatter.

BUT: the format given above will give multiplier outputs for repetitive characters

$ printf "Hello" | hexdump -e '/1 "%02X"' 48656C* 6F 

instead of

48656c6c6f 

Comments

0
jcomeau@aspire:~$ echo -n The quick brown fox jumps over the lazy dog | python -c "print raw_input().encode('hex')," 54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67 jcomeau@aspire:~$ echo -n The quick brown fox jumps over the lazy dog | python -c "print raw_input().encode('hex')," | python -c "print raw_input().decode('hex')," The quick brown fox jumps over the lazy dog 

it could be done with Python3 as well, but differently, and I'm a lazy dog.

4 Comments

python != bash
neither are sed, hexdump, printf, awk, or xxd.
it's shorter than some of the other solutions and arguably more readable. and it converts both ways, from the Bash command line. I don't see your point.
The point is, he asked for a bash solution. Meaning, as per his context, bashisms or bash built-ins. You didn't provide this with python solution(s).
0

ascii to hex

echo -en 'hello\nyou\nthere' | sed -z "s/\(.\)/'\1\x0/g" | xargs -0 printf '%02x' 
68656c6c6f0a796f750a7468657265 

hex to ascii

echo '68656c6c6f0a796f750a7468657265' | sed 's/\(..\)/\\\\x\1/g' | xargs printf 
hello you there 

Comments

-2

echo append a carriage return at the end.

Use

echo -e 

to remove the extra 0x0A

Also, hexdump does not work byte-per-byte as default. This is why it shows you bytes in a weird endianess and why it shows you an extra 0x00.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.