Sounds to me like you don't really need all the characters...
$ awk 'BEGIN { chartable="abcdefghij" ; for (i=index(chartable, "a"); i<index(chartable, "g"); i++) { print substr(chartable, i, 1) } }'
a
b
c
d
e
f
Answer from Ignacio Vazquez-Abrams on Stack ExchangeSounds to me like you don't really need all the characters...
$ awk 'BEGIN { chartable="abcdefghij" ; for (i=index(chartable, "a"); i<index(chartable, "g"); i++) { print substr(chartable, i, 1) } }'
a
b
c
d
e
f
Build a table containing all the ASCII characters and use the awk builtin index() to lookup characters in the table. Then use sprintf() to convert the decimal value returned by index() to hex.
BEGIN {
for (i = 0; i < 128; i++) {
table = sprintf("%s%c", table, i);
}
}
function chartohex (char) {
return sprintf("0x%x", index(table, char));
}
END { # examples
print chartohex("a");
print chartohex("A");
print chartohex("!");
}
Put this code in the file "foo" and run awk -f foo < /dev/null and you'll see the ASCII values for "a", "A" and "!" printed in hexadecimal.
xxd - awk command to map ASCII char to hex code not working - Unix & Linux Stack Exchange
Convert column from hex to ascii
convert hex to ascii
Bash. Hex to ascii. Is possible without xxd or perl? - Stack Overflow
No, \nnn is octal and \xnn is hex - that's all there is for including characters you cannot include as-is in strings and you should always use the octal, not the hex, representation for robustness (see, for example, http://awk.freeshell.org/PrintASingleQuote).
I don't understand the last part of your question where you state what you're trying to do with this - provide concise, testable sample input and expected output and I'm sure someone can help you do it the right way, whatever it is.
Is this what you're trying to do?
$ awk 'BEGIN{for (i=0141; i<0143; i++) print i}'
97
98
A lookup table is the only way to address this (directly convert CHAR to ASCII DECIMAL) within "AWK only".
You can simply use sprintf() to convert ASCII DECIMAL to CHAR.
You can create a lookup table by iterating through each of the known ascii chars and storing them in an array where the key is the character and the value is the ascii value of that char.
You can use sprintf() within AWK to get the char for each decimal.
Then you can pass the char to the array to get the corresponding decimal again.
In this example, using awk.
- We cycle through all 256 characters, printing out each one.
- We split the resulting string into a series of lines where each line has a single character.
- We build a table in awk of the 256 characters (in BEGIN), and then feed each of the input characters in to lookup each one.
- Finally we then print out the code for each character on the input.
awk 'BEGIN{ for(n=0;n<256;n++) print sprintf("%c",n) }' | awk '{ for (i=0; ++i <= length($0);) printf "%s\n", substr($0, i, 1) }' | awk 'BEGIN{ for(n=0;n<256;n++) ord[sprintf("%c",n)]=n }{ print ord[$1] }'
The reverse can also be done, where we lookup a list of character codes.
awk 'BEGIN{ for(n=0;n<256;n++) print sprintf("%s",n) }' | awk 'BEGIN{ for(n=0;n<256;n++) char[n]=sprintf("%c",n) }{ print char[$1] }'
Note: The second example may print out a lot of garbage in the high ascii range (> 128) depending on the character set you are using.
It sounds like your goal is to learn (about) awk rather than to simply get the ASCII table, which per other answer is easily available.
You don't need any input file(s) for this; you can directly display all the printable characters with
awk 'BEGIN{ for(i=32;i<127;i++) printf("%02x %c\n",i,i) }'
(This generates one long column, as your attempt did; if you want multicolumns that's left as an exercise.)
OTOH if you want to combine pairs of fields from two lines -- which can be any values not just a char and its hex:
awk [-Fasneeded] 'NR==1 { for(i=1;i<=NF;i++) save[i]=$i; next }
{ for(i=1;i<=NF;i++) print save[i],$i }' file ...
# linebreak for ease of reading, may be omitted in use
This works whether the two lines come from two files, as in your case, or one file. If you have more than two lines, this pairs fields from line 1 to each subsequent line, a pattern that often makes sense for CSV-type files which have a header on line 1 with names for each column, followed by a variable number of lines with data in each column.
This also preserves the order including any dupes. To eliminate dupes but otherwise keep order:
awk [-Fasneeded] 'NR==1 { for(i=1;i<=NF;i++) save[i]=$i; next }
{ for(i=1;i<=NF;i++) if(!dupe[$i]++) print save[i],$i ;delete dupe }' file ...
# the delete dupe can be omitted in the two-line case
If you actually want the random order created by for in that's also possible, but it makes no sense to me. Some useful order such as numerical order or alphabetical order (with dupes eliminated) might make sense.
If you use the GNU awk, then you can include the extended library ordchr:
echo abshdfitiggwigiwjirjgiejrigjr |
awk -lordchr -F '' '{for(i=1;i<=NF;i++)printf "%c %x\n",
i)}'
a 61
b 62
s 73
h 68
...
ord() - function, convert char to decimal
printf "%x", ord($i) - convert decimal to hex
Additionally: chr() - convert decimal to char
Hi! I need help with something, I have a tab separated file with one column (number 6) with values in hex, I need to convert them to ascii text.
I can modify the column using awk but I can't pass that value to another command to do the convertion. Is it possible to do something like this?
Thanks!
Found this script here:
#!/bin/bash
function hex2string () {
I=0
while [ $I -lt ${#1} ];
do
echo -en "\x"${1:$I:2}
let "I += 2"
done
}
hex2string "31323334353637383930313233"
echo
You may change the line hex2string "31323334353637383930313233" so that it takes the hex value from parameters, that is:
#!/bin/bash
function hex2string () {
I=0
while [ $I -lt ${#1} ];
do
echo -en "\x"${1:$I:2}
let "I += 2"
done
}
hex2string "$1"
echo
So when executed as:
./hexstring.sh 31323334353637383930313233
It will provide the desired ascii output.
NOTE: Can't test if it works in all Linux systems.
Using gawk, from HEX to ASCII
$ gawk '{
gsub(/../,"0x& ");
for(i=1;i<=NF;i++)
printf("%c", strtonum($i));
print ""
}' <<<"31323334353637383930313233"
1234567890123
Using any awk
$ cat hex2asc_anyawk.awk
BEGIN{
split("0 1 2 3 4 5 6 7 8 9 A B C D E F", d, / /)
for(i in d)Decimal[d[i]]=i-1
}
function hex2dec(hex, h,i,j,dec)
{
hex = toupper(hex);
i = length(hex);
while(i)
{
dec += Decimal[substr(hex,i,1)] * 16 ^ j++
i--
}
return dec;
}
{
gsub(/../,"& ");
for(i=1;i<=NF;i++)
printf("%d",hex2dec($i));
print ""
}
Execution
$ awk -f hex2asc_anyawk.awk <<<"31323334353637383930313233"
1234567890123
Explanation
Steps :
Get the decimal equivalent of hex from table.
Multiply every digit with 16 power of digit location.
Sum all the multipliers.


Example :

BEGIN{
# Here we created decimal conversion array, like above table
split("0 1 2 3 4 5 6 7 8 9 A B C D E F", d, / /)
for(i in d)Decimal[d[i]]=i-1
}
function hex2dec(hex, h,i,j,dec)
{
hex = toupper(hex); # uppercase conversion if any A,B,C,D,E,F
i = length(hex); # length of hex string
while(i)
{
# dec var where sum is stored
# substr(hex,i,1) gives 1 char from RHS
# multiply by 16 power of digit location
dec += Decimal[substr(hex,i,1)] * 16 ^ j++
i-- # decrement by 1
}
return dec;
}
{
# it modifies record
# suppose if given string is 31323334353637383930313233
# after gsub it becomes 31 32 33 34 35 36 37 38 39 30 31 32 33
# thus re-evaluate the fields
gsub(/../,"& ");
# loop through fields , NF gives no of fields
for(i=1;i<=NF;i++)
# convert from hex to decimal
# and print equivalent ASCII value
printf("%c",hex2dec($i));
# print newline char
print ""
}
Meaning of
dec += Decimal[substr(hex,i,1)] * 16 ^ j++
dec += Decimal[substr(hex,i,1)] * 16 ^ j++
^ ^ ^
| | |
| | 2.Multiply every digit with 16 power of digit location.
| |
| 1.Gives decimal equivalent of hex
|
|
3. Sum all the multipliers
If you don't have to use awk, you might look at od ("octal dump"):
$ echo 1A34532112345 | od -t x1
0000000 31 41 33 34 35 33 32 31 31 32 33 34 35 0a
0000016
awk will silently convert strings to numbers. Which number? The number you get by taking the initial decimal digits of the string (this may be just "", if the string is empty or doesn't begin with any decimal digits, as is the case with "A") and converting them to a number. "" gets converted to 0. So all of these would be converted to 0:
- "0"
- "0text"
- "text"
- ""
awk only converts strings to numbers in this way when a number is needed. In "0text" + 1, a number is needed, so the result will be 1. In just plain "0text", a number isn't needed, so no conversion takes place. In printf("%d", "0text"), a number again is needed, so the string will be converted to a number.
What you are looking for is an ord function, which isn't a native function in awk. The gawk documentation describes how to write such a function in awk.
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.
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
Your input file looks like it was produced using something like this:
hexdump -e '"%08_ad " 8/1 "%04x "' -e '"" 0/0 "" "\n"' original_file
Unfortunately, xxd -r can't deal with decimal offsets.
Here is a short Gnu AWK program to give you the output you're looking for:
gawk '{printf "%s |", $0; for (f=2; f<=9; f++) { c = strtonum("0x" $f); if (c >= 32 && c <= 126) printf "%c",c; else printf "."}; printf "|\n"}' input_file
If you're using an AWK other than gawk, you can use the strtonum() function here.
Here's another way to do the same thing as the gawk script above:
cut -c 11- input_file | sed 's/\<00//g' | xxd -r -p | hexdump -e '"%08_ad " 8/1 "%04x " ""' -e '" |" 8/1 "%_p" "|\n"'
If, instead, you want to convert your input file to text:
cut -c 11- input_file | xxd -r -p
iconv -f utf-16be -t ascii input.txt
This worked for me.
$ echo -n 54657374696e672031203220330 | xxd -r -p
Testing 1 2 3$
echo -n prevents a newline from being added to the end
-r tells it to convert hex to ascii as opposed to its normal mode of doing the opposite
-p tells it to use a plain format.
This code will convert the text 0xA7.0x9B.0x46.0x8D.0x1E.0x52.0xA7.0x9B.0x7B.0x31.0xD2 into a stream of 11 bytes with equivalent values. These bytes will be written to standard out.
TESTDATA=$(echo '0xA7.0x9B.0x46.0x8D.0x1E.0x52.0xA7.0x9B.0x7B.0x31.0xD2' | tr '.' ' ')
for c in $TESTDATA; do
echo $c | xxd -r
done
As others have pointed out, this will not result in a printable ASCII string for the simple reason that the specified bytes are not ASCII. You need post more information about how you obtained this string for us to help you with that.
How it works: xxd -r translates hexadecimal data to binary (like a reverse hexdump). xxd requires that each line start off with the index number of the first character on the line (run hexdump on something and see how each line starts off with an index number). In our case we want that number to always be zero, since each execution only has one line. As luck would have it, our data already has zeros before every character as part of the 0x notation. The lower case x is ignored by xxd, so all we have to do is pipe each 0xhh character to xxd and let it do the work.
The tr translates periods to spaces so that for will split it up correctly.