0

I create bash scripts which get sourced from another "main" script to set up variables needed by the main script. These variables need to be able to contain any character and not have them interpreted by the shell. For example:

  • a single quote: '
  • dollar sign: $
  • asterix: *
  • pound sign: #, etc.

So, my thinking was to use a single quote and escape any enclosed single quotes and # characters. But, am getting a unexpected EOF while looking for matching error with the two files below.

Question:

  1. What is the best way to define a string which can contain any set of characters that would require the least amount of tweaking?

    There are thousands of such foo.sh files and as the string is being extracted form another source, I want to minimize the number of special characters that I need to escape.

  2. What other characters do I need to escape.

The desired output form the following scripts below is

\MyMacro{*,Baker's Dozen,$x^$,#}

Platform:

  • MacOS 10.9.5

Sub Shell: foo.sh

set -f
string_list='*,Baker\'s Dozen,$x^$,\#'
set +f

Main Shell: main.sh

source foo.sh
printf "%s{%s}" "\MyMacro" "${string_list}"
1

You don't have to escape # inside quote, and it's weird to have literal single quote inside single quote:

string_list='*,Baker'\''s Dozen,$x^$,#'

But it's easier with double quotes. So something like:

string_list="*,Baker's Dozen,\$x^\$,#"

will work.

You only need "\"" for double quote, instead of ''\''' for single quote, and also escaping $ to prevent variable expansion.

If you want to minimize the escaping, then change any ' inside single quote to '"'"':

string_list='*,Baker'"'"'s Dozen,$x^$,#'
1

You can avoid any escaping, but with a bit more overhead, by using something like this:

string_list=$(cat <<\!eof!
*,Baker's Dozen,$x^$,#
!eof!
)

where you cat stdin which is a here-is document that will have no processing done to it. You can even have backslashes, single and double quotes, whitespace and multiple lines in the string. To be a bit more efficient you can use this:

read string_list <<\!eof!
*,Baker's Dozen,$x^$,#
!eof!

but you will lose any initial whitespace and any backslashes.

  • Since one of the requirements is to be able to store any character, it should be noted that the command substitution approach cannot handle a single newline or trailing newlines. read strips the delimiter, so it cannot appear in the string. – Barefoot IO Feb 25 '16 at 19:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.