Escape double quotes in variable

7,099

I think this is safe:

esc() {
    printf "%s\n" "$1" | sed -e "s/'/'\"'\"'/g" -e "1s/^/'/" -e "\$s/\$/'/"
}

It single-quotes the string, so that any $, `, \, and " in the input string don't matter, and turns any existing ' characters into '"'"' (i.e. end single-quoting, double-quote a lone single-quote, then reënter single-quoting).

It was tempting to use $(...) command substitution in there, except that then it will eat any trailing newlines in the input. Instead the opening and closing quotes are inserted by the second and third sed scripts themselves, at the start of the first line and the end of the last line. Any embedded newlines are left raw, which is fine.

The output is suitable for copying back into the shell, even in the most pathological case I can invent (using Bash ANSI-C quoting $'...' to create the test string in the first place, but not afterwards):

bash-4.4$ esc $'abc\ndef ghi\'jkl$mno`pqr\\stu\\\'vwx\n\n\n'
'abc
def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx


'
bash-4.4$ echo 'abc
> def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx
>
>
> '
abc
def ghi'jkl$mno`pqr\stu\'vwx



bash-4.4$ dash
$ echo 'abc
def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx


'> > > >
abc
def ghi'jkl$mno`pqr\stu\'vwx



$

It's safe to put that into a variable xr=$(esc "$xr") and then use that in ordinary substitution later on within your here-document or elsewhere.

Share:
7,099

Related videos on Youtube

user1730706
Author by

user1730706

Hello world

Updated on September 18, 2022

Comments

  • user1730706
    user1730706 over 1 year

    I would like to put this command into a file to be run later:

    ln -s "$xr"/ya.txt ~
    

    I can do that with (1):

    cat > zu.sh <<eof
    ln -s "$xr"/ya.txt ~
    eof
    

    or (2):

    printf 'ln -s "%s"/ya.txt ~\n' "$xr" > zu.sh
    

    or (3):

    echo "ln -s '$xr'/ya.txt ~" > zu.sh
    

    or (4):

    printf 'ln -s %q/ya.txt ~\n' "$xr" > zu.sh
    

    or (5):

    printf 'ln -s "%s"/ya.txt ~\n' "${xr//\"/\\\"}"
    

    however each solution is problematic. if the variable in (1) or (2) contains a double quote, they will fail; if the variable in (3) contains a single quote, it will fail. (4) is good but is not defined by POSIX. (5) is good but is a Bashism. it looks like the best option would be to use (1) or (2) and escape any double quotes in the variable, but can that be done another way?