ksh88 changing single quotes to double quotes insi

2019-01-18 13:20发布

问题:

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?

回答1:

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)
    


标签: shell ksh aix