25

I would like to print out augments of a function to a file. I was told a command printf "%q ", whose instruction is following,

# man printf
%q     ARGUMENT is printed in a format that can be reused as shell input, escaping non-print‐
          able characters with the proposed POSIX $'' syntax.

On the basis of instruction above, I tried following code.

#!/bin/bash
# file name : print_out_function_augs.sh

output_file='output.txt'

function print_augs() {
  printf "%q " "$@" >> "${output_file}"
  echo >> "${output_file}"
}

print_augs a 'b c'

cat "${output_file}"
rm "${output_file}"

and run

bash print_out_function_augs.sh

The results are following,

a b\ c

I expected the results as

a 'b c'

which is the original augments to print_augs function.

Why does the output and the original augments are different? Or can I print out the original augments as they are?

Thank you very much.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
mora
  • 2,217
  • 4
  • 22
  • 32

1 Answers1

32

Bear this in mind when using %q:

ARGUMENT is printed in a format that can be reused as shell input, escaping non-printable characters with the proposed POSIX $'' syntax.

Emphasis mine. printf is free to reformat the arguments any way it likes as long as the input can be reused in the shell. However this is not the reason your input looks the way it does.

In Bash the ' character is a string delimiter, which is how you tell bash "the following string contains special characters like spaces, and these special characters should not be parsed by Bash". The quotes do not get passed to the commands that get called. What the command sees is something like this:

Command:
  printf "%q" a 'b c'

Received args:
  printf::arg0:  printf
  printf::arg1:  %q
  printf::arg2:  a
  printf::arg3:  b c

Note that arg3 does not have the quotes surrounding it. Bash does not pass them on.

When printf prints the args out, it does not know that there were quotes around b c, so it does not print them. But it does know that the space between 'b' and 'c' is a special shell character, and puts the \ in front to escape it.

This is true for all bash functions/commands, so bear in mind that the same happens when you call print_augs too.

If you want to maintain quotes around your strings, you'll need to double quote them so that Bash doesn't parse them:

function print_augs2() {
  echo "$@" >> "${output_file}"
}

print_augs2 a "'b c'"

# Output: a 'b c'
Karl Nicoll
  • 16,090
  • 3
  • 51
  • 65
  • thank you for detailed explanation and solutions. I could not imagin '\' in 'b\ c'. is a escape character. – mora Nov 13 '16 at 13:08