17

I wanted to output a string of all the ascii characters with the following command

for i in `seq 32 127`; do printf "%c" $i; done

The output of the above command is:

33333334444444444555555555566666666667777777777..............

It's the first (from the left) digit of each number.

Looking through this site I came across the answer to my problem How to print all printable ASCII chars in CLI?, however I still don't understand why my original snippet does not output the ascii characters as intended.

2
  • 1
    POSIX dictates this, here's a comp.unix.shell thread on why it's the right thing ;)
    – sr_
    Aug 4, 2012 at 11:36
  • @sr_ Thanks for pointing out the thread. It had the explanation I was looking for.
    – Ifthikhan
    Aug 4, 2012 at 18:06

4 Answers 4

16

You can't directly print the ascii codes by using the printf "%c" $i like in C.

You have to first convert the decimal value of i into its octal value and then you have to print it using using printf and putting \ in front of their respective octal values.

To print A, you have to convert the decimal 65 into octal, i.e. 101, and then you have to print that octal value as:

printf "\101\n"

This will print A.

So you have to modify it to :

for i in `seq 32 127`; do printf \\$(printf "%o" $i);done;

But by using awk you can directly print like in C language

awk 'BEGIN{for(i=32;i<=127;i++)printf "%c",i}';echo
4
  • 8
    In bash and zsh this can be done without the loop and without the external command: printf $(printf '\%o' {32..127}).
    – manatwork
    Aug 4, 2012 at 12:02
  • @manatwork: ya exactly..thanks a lot for pointing it out.. Aug 4, 2012 at 12:08
  • 1
    @pradeepchhetri : Thank you for the detailed response and it seemed to cover most of the required details (hence I choose your answer). However I guess it missed out an important piece of information which can be found in the following message at unix.derkeiler.com/Newsgroups/comp.unix.shell/2007-07/…. It states that "The argument operands shall be treated as strings if the corresponding conversion specifier is b, c, or s..."
    – Ifthikhan
    Aug 4, 2012 at 18:11
  • Isn't (char)(127) backspace or something like that. Whatever it is, it appears as one of the hex-boxes or whatever they are called. If you want only the "printable" (i.e. readable), just go to 126. Also, nice thought with the octal. That's clever; I was thinking in terms of hexadecimal (like printf '\x%x; {32..126} ... or 127, I guess, since all of you did it, too), but it doesn't work. Octal saves the day! :) Finally, @Ifthikhan, I'm not sure what you mean. awk often uses C-style commands and nowhere else is %c used. Using octal numbers is different than using one-byte characters.
    – Dylan
    Nov 20, 2014 at 14:31
3

%c Interprets the associated argument as char: only the first character of a given argument is printed

You seem to already have a way to print them, but here is one variant.

for i in `seq 32 127`; do printf "\x$(printf "%x" $i) $i"; done
0
1

You need printf, but only once; you can replace one use of printf by the simpler and more efficient echo plus Bash escape sequences:

With hexagesimals:

for i in `seq 32 127`; do
  echo -ne \\x$(printf %02x $i)
done

With octals:

for i in `seq 32 127`; do
  echo -ne \\0$(printf %03o $i)
done
0

If, like me, you prefer keeping the printf format string as constant as possible, change:

for i in `seq 32 127`; do printf "\\$(printf %o "$i")"; done
for i in `seq 32 127`; do printf "\x$(printf %x "$i")"; done  # not POSIX

to

for i in `seq 32 127`; do printf %b "\0$(printf %o "$i")"; done
for i in `seq 32 127`; do printf %b "\x$(printf %x "$i")"; done  # not POSIX

(Incidentally, the POSIX standard for printf doesn't include \x among the escape sequences allowed in the format string.)

I prefer keeping the printf format string as constant as possible because of separation of concerns. The format string's concern is formatting; the arguments are for data that varies. Also a problem could occur if an expansion in the format string includes things that could be interpreted as format specifiers, as discussed here in the context of C programming. Also discussed here: ShellCheck linting rule SC2059 Don't use variables in the printf format string.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .