Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ksh88 changing single quotes to double quotes inside heredocs?

Tags:

shell

ksh

aix

I seem to be running into an issue that's specific to ksh88 that's changing single quotes to double quotes, but only under certain situations involving heredocs and command substitution.

Here's an example:

#!/bin/ksh

# This example works correctly
echo "Example 1:"
cat <<EOF
The 'quick' brown fox "jumped" over the lazy dog.
EOF
echo


# This example is broken
echo "Example 2:"
var=$(cat <<EOF
The 'quick' brown fox "jumped" over the lazy dog.
EOF)
echo "${var}"
echo


# This example works correctly
echo "Example 3:"
var=`cat <<EOF
The 'quick' brown fox "jumped" over the lazy dog.
EOF`
echo "${var}"
echo

And here's the output (note how Example 2 is different):

Example 1:
The 'quick' brown fox "jumped" over the lazy dog.

Example 2:
The "quick" brown fox "jumped" over the lazy dog.

Example 3:
The 'quick' brown fox "jumped" over the lazy dog.

The ' to " substitution seems to occur before the command runs. In actual context, the heredoc is passing SQL to Oracle. By changing ' to ", strings are being converted to identifiers, thus breaking the SQL. This can also be observed by enabling xtrace during execution of the above code.

How can I prevent the ' to " conversion in the above code snippet without using backticks?


Edit: The plot thickens. Replacing the command substituion $( ... ) with backtick notation doesn't replace the single quotes with double quotes. So (optional) question two: why?

like image 523
Mr. Llama Avatar asked Aug 29 '14 13:08

Mr. Llama


People also ask

How do you change single quotes to double quotes?

Use the String. replace() method to replace double with single quotes, e.g. const replaced = str. replace(/"/g, "'"); . The replace method will return a new string where all occurrences of double quotes are replaced with single quotes.

How do you put single quotes inside quotes?

' End first quotation which uses single quotes. " Start second quotation, using double-quotes. ' Quoted character. " End second quotation, using double-quotes.

How do you ignore a single quote in a string?

A single quote is not used where there is already a quoted string. So you can overcome this issue by using a backslash following the single quote.

What's the difference between a single quote and a double quote in bash?

Single quotes won't interpolate anything, but double quotes will. For example: variables, backticks, certain \ escapes, etc. Enclosing characters in single quotes ( ' ) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.


1 Answers

Here are my notes when I discovered this same bug several years ago.

Test script:

#!/bin/ksh
cat <<EOF
  $PWD "$PWD" '$PWD'
EOF
echo `cat <<EOF
  $PWD "$PWD" '$PWD'
EOF
`
echo $(cat <<EOF
  $PWD "$PWD" '$PWD'
EOF
)

Output for different shells:

  • Linux KSH Version M 1993-12-28 q
  • Linux Bash 3.00.15(1)

(NOTE: works as expected)

 /home/jrw32982 "/home/jrw32982" '/home/jrw32982'
 /home/jrw32982 "/home/jrw32982" '/home/jrw32982'
 /home/jrw32982 "/home/jrw32982" '/home/jrw32982'
  • AIX Version M-11/16/88f
  • Solaris Version M-11/16/88i

(NOTE: single quotes replaced with double quotes and variable not substituted)

 /home/jrw32982 "/home/jrw32982" '/home/jrw32982'
 /home/jrw32982 "/home/jrw32982" '/home/jrw32982'
 /home/jrw32982 "/home/jrw32982" "$PWD"

Work-around:

  1. Compute the single-quoted string externally from the here-file

    abc=xyz
    STR="'$abc'"
    x=$( cat <<EOF
      $abc "$abc" $STR
    EOF
    )
    
  2. Use the here-file in a function instead of directly

    fn() {
      cat <<EOF
        $abc "$abc" '$abc'
    EOF
    }
    abc=xyz
    x=$(fn)
    
like image 196
jrw32982 Avatar answered Nov 15 '22 20:11

jrw32982