121

Character to value works:

$ printf "%d\n" \'A 65 $ 

I have two questions, the first one is most important:

  • How do I take 65 and turn it into A?
  • \'A converts an ASCII character to its value using printf. Is the syntax specific to printf or is it used anywhere else in BASH? (Such small strings are hard to Google for.)
1
  • 3
    @schnaader but you can not script that. Commented Apr 14, 2015 at 20:33

13 Answers 13

100

One line

printf "\x$(printf %x 65)" 

Two lines

set $(printf %x 65) printf "\x$1" 

Here is one if you do not mind using awk

awk 'BEGIN{printf "%c", 65}' 
Sign up to request clarification or add additional context in comments.

1 Comment

Should work as well printf "$(printf '\\x%02x' $char)"
54

This works (with the value in octal):

$ printf '%b' '\101' A 

even for (some: don't go over 7) sequences:

$ printf '%b' '\'{101..107} ABCDEFG 

A general construct that allows (decimal) values in any range is:

$ printf '%b' $(printf '\\%03o' {65..122}) ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz 

Or you could use the hex values of the characters:

$ printf '%b' $(printf '\\x%x' {65..122}) ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz 

You also could get the character back with xxd (use hexadecimal values):

$ echo "41" | xxd -p -r A 

That is, one action is the reverse of the other:

$ printf "%x" "'A" | xxd -p -r A 

And also works with several hex values at once:

$ echo "41 42 43 44 45 46 47 48 49 4a" | xxd -p -r ABCDEFGHIJ 

or sequences (printf is used here to get hex values):

$ printf '%x' {65..90} | xxd -r -p ABCDEFGHIJKLMNOPQRSTUVWXYZ 

Or even use awk:

$ echo 65 | awk '{printf("%c",$1)}' A 

even for sequences:

$ seq 65 90 | awk '{printf("%c",$1)}' ABCDEFGHIJKLMNOPQRSTUVWXYZ 

1 Comment

The final example can even be extended to create a dynamically-generated ASCII table: seq 98 102 | awk 'BEGIN{print "\n\tDEC\tOCT\tHEX\tCharacter\n\t---\t---\t--\t-"}; {printf("\t%d\t%o\t%x\t%c\n",$1,$1,$1,$1)}; END{printf "\n"}' {Thanks also to this answer to a different question}
24

For your second question, it seems the leading-quote syntax (\'A) is specific to printf:

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.

From https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

Comments

14

One option is to directly input the character you're interested in using hex or octal notation:

printf "\x41\n" printf "\101\n" 

3 Comments

+1 for a solution that works even if we don't have the % character on our keyboard :D I was using a Linux terminal from postmarketOS on Nokia N900 and wanted to print it to copy-paste it in commands :)
I had to test whether a character was a CarriageReturn (\r) in a bash script and I found I had to use the following: testchar=$'\r'; if [ ${testchar} = $'\r' ]; then echo "is true"; else echo "is false"; fi. ASCII hex can be used in place of \r, ie. $'\x0D'. However, the string "\r", or the hex equivalent, didn't work for the conditional, always returning false.
I can't find \x in the printf man page. Where is this documented? TIA
9

For this kind of conversion, I use perl:

perl -e 'printf "%c\n", 65;' 

1 Comment

or in perl, print chr(65), "\n"; While perl might be a good choice if you're doing a lot of this, using the shell's printf to convert your number into something that can go into a \0 escape sequence works just fine. More complex with unicode, as you need \u support in your printf.
9

If you want to save the ASCII value of the character: (I did this in BASH and it worked)

{ char="A" testing=$( printf "%d" "'${char}" ) echo $testing} 

output: 65

1 Comment

This worked, thanks. I wanted to get an Integer (ASCII code) from a typed character. I made a script: {read -n 1 c; echo $( printf "%d" "'${c}" )}
9

If you convert 65 to hexadecimal it's 0x41:

$ echo -e "\x41" A

1 Comment

if you know the hex value to print ASCII character $ printf "\x41"
7

For capital letters:

i=67 letters=({A..Z}) echo "${letters[$i-65]}" 

Output:

 C 

1 Comment

Btw.: In the opposite direction: printf -v num "%d" "'C"; echo "$num"
4

Here's yet another way to convert 65 into A (via octal):

help printf # in Bash man bash | less -Ip '^[[:blank:]]*printf' printf "%d\n" '"A' printf "%d\n" "'A" printf '%b\n' "$(printf '\%03o' 65)" 

To search in man bash for \' use (though futile in this case):

man bash | less -Ip "\\\'" # press <n> to go through the matches 

1 Comment

Thank you for the manpage parsing example!
2

this prints all the "printable" characters of your basic bash setup:

printf '%b\n' $(printf '\\%03o' {30..127}) !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 

1 Comment

you're sure \36 \37 and \177 are all that "printable" ?
1

Here is a solution without eval nor $() nor `` :

ord () { local s printf -v s '\\%03o' $1 printf "$s" } ord 65 

Comments

0

Given that there are not that many 1-byte characters, but only 256, they can quickly be precomputed at your script startup:

declare -ag CHARS=() for REPLY in {{0..9},{a..f}}{{0..9},{a..f}}; do printf -v CHARS[${#CHARS[@]}] "\x$REPLY" done 

(I reused the discardable REPLY variable, but you can local your own inside an init function)

Then...

$ echo "${CHARS[65]}" A $ i=65 $ echo "${CHARS[i]}" A 

Beware of \x00, whose value is not properly handled in Bash because it is the string terminator character:

$ var=$'qwe\x00rty' $ echo ${#var} 3 $ echo "<${var}>" <qwe> 

So, "${CHAR[0]}" will always be a problem under Bash.

This way, you avoid output capture, inline text substitution and re-parsing once and again for every time you need to process one character; which is even worse for subprocess IPC through xxd, awk or perl.

Comments

0

The following script prints aaa...zzz (i.e. aaa > aab > aac > ... > zzx > zzy > zzz)

for i in $(seq 0 25); do first=$(printf \\$(printf '%03o' $((97+i)) )) for f in $(seq 0 25); do second=$(printf \\$(printf '%03o' $((97+$f)) )) for g in $(seq 0 25); do third=$(printf \\$(printf '%03o' $((97+$g)) )) echo "${first}${second}${third}" done done done 

The core of the functionality here is that printf '%03o' 97 prints the octal value of 97 i.e. 141; and printf \\141 prints the character it corresponds to.

Comments