How can I escape a double quote inside double quotes?
Asked Answered
A

10

419

How can I escape double quotes inside a double string in Bash?

For example, in my shell script

#!/bin/bash

dbload="load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"

I can't get the ENCLOSED BY '\"' with double quote to escape correctly. I can't use single quotes for my variable, because I want to use variable $dbtable.

Apelles answered 30/9, 2010 at 21:5 Comment(9)
Also see mywiki.wooledge.org/BashFAQ/050Luckless
possible duplicate of Escaping single-quotes within single-quoted stringsInsolate
@Insolate Doesn't look like a duplicate of that question...Kahlil
See also #10067766Synchrotron
@Daenyth This isn't the type of command you'd expect end users to have any access to. Bulk load scripts are usually run on the server by trusted users (such as system admins or developers). Yes, if end users control the value of $dbtable, there's a risk. This would be very uncommon, though, as end users don't typically SSH into a machine to load their data.Serica
@Serica Malicious input isn't the only case - loading from a csv could easily include data that's invalid sql just by accident.Rustin
@Rustin The CSV is never parsed as SQL.... It's parsed by an explicit CSV parsing command that inserts the values into a table.Serica
See also: Difference between single and double quotes in Bash.Curcio
The canonical for single quotes: How to escape single quotes within single quoted stringsHachmann
C
390

Use a backslash:

echo "\""     # Prints one " character.
Cantabrigian answered 30/9, 2010 at 21:7 Comment(4)
Not working. x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi; gives broken whereas ... [ -f "$(which $x)" ]; ... or ... [ -f $(which "$x") ]; ... work just fine. Issues would arise when either $x or the result of $(which "$x") gives anything with a space or other special character. A workaround is using a variable to hold the result of which, but is bash really incapable of escaping a quote or am I doing something wrong?Tuckie
I am trying to use the following grep -oh "\"\""$counter"\""\w*" as part of a bash syntax where in $counter is a variable. it doesn't like it any thoughtsTevis
@AndroidEngineX, this method works fine when used correctly. Luc's comment above is using it wrong; they're telling which to search for an executable that has literal quotes in its name, and of course no such thing exists. That's Luc's own problem, not a mistake with this answer.Luckless
@JayD, \w doesn't work in POSIX-standard grep at all in the first place. It's a PCRE extension, and grep only supports BRE and ERE. I couldn't evaluate your comment more than that without knowing what strings you expect to match / how you're testing.Luckless
I
148

A simple example of escaping quotes in the shell:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

It's done by finishing an already-opened one ('), placing the escaped one (\'), and then opening another one (').

Alternatively:

$ echo 'abc'"'"'abc'
abc'abc
$ echo "abc"'"'"abc"
abc"abc

It's done by finishing already opened one ('), placing a quote in another quote ("'"), and then opening another one (').

More examples: Escaping single-quotes within single-quoted strings

Insolate answered 28/2, 2015 at 20:50 Comment(3)
I tried sh -c "echo '{"key":"value"}'" and even sh -c "echo '{''"''key''"'':''"''value''"''}'" in an effort to enclose the words key and value in double quotes, but in both cases I got {key:value}Manned
This seems unnecessarily complicated for double quotes: echo "abc\"abc" is sufficient to produce abc"abc as in Peter answer.Misogamy
In this simple example indeed, but in complex cases of nested quotes, it can be necessary to do this and @kenorb's example helped me figure out how to deal with those cases.Nodus
S
93

Keep in mind that you can avoid escaping by using ASCII codes of the characters you need to echo.

Example:

echo -e "This is \x22\x27\x22\x27\x22text\x22\x27\x22\x27\x22"
This is "'"'"text"'"'"

\x22 is the ASCII code (in hex) for double quotes and \x27 for single quotes. Similarly you can echo any character.

I suppose if we try to echo the above string with backslashes, we will need a messy two rows backslashed echo... :)

For variable assignment this is the equivalent:

a=$'This is \x22text\x22'
echo "$a"

# Output:
This is "text"

If the variable is already set by another program, you can still apply double/single quotes with sed or similar tools.

Example:

b="Just another text here"
echo "$b"

 Just another text here

sed 's/text/"'\0'"/' <<<"$b" #\0 is a special sed operator
 Just another "0" here #this is not what i wanted to be

sed 's/text/\x22\x27\0\x27\x22/' <<<"$b"

 Just another "'text'" here #now we are talking. You would normally need a dozen of backslashes to achieve the same result in the normal way.
Selfpronouncing answered 20/2, 2017 at 10:17 Comment(2)
+1 because it solved a problem of adding a PS1 variable to ~/.profile echo 'export PS1='\[\033[00;31m\]${?##0}$([ $? -ne 0 ] && echo \x22 \x22)\[\033[00;32m\]\u\[\033[00m\]@\[\033[00;36m\]\h\[\033[00m\][\[\033[01;33m\]\d \t\[\033[00m\]] \[\033[01;34m\]\w\n\[\033[00m\]$( [ ${EUID} -ne 0 ] && echo \x22$\x22 || echo \x22#\x22 ) '' >> ~/.profileGranuloma
This is THE answer! I love u Sir.Bouton
D
37

Bash allows you to place strings adjacently, and they'll just end up being glued together.

So this:

echo "Hello"', world!'

produces

Hello, world!

The trick is to alternate between single and double-quoted strings as required. Unfortunately, it quickly gets very messy. For example:

echo "I like to use" '"double quotes"' "sometimes"

produces

I like to use "double quotes" sometimes

In your example, I would do it something like this:

dbtable=example
dbload='load data local infile "'"'gfpoint.csv'"'" into '"table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"'"'"' LINES "'TERMINATED BY "'"'\n'"'" IGNORE 1 LINES'
echo $dbload

which produces the following output:

load data local infile "'gfpoint.csv'" into table example FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "'\n'" IGNORE 1 LINES

It's difficult to see what's going on here, but I can annotate it using Unicode quotes. The following won't work in Bash – it's just for illustration:

dbload=load data local infile "’“'gfpoint.csv'”‘" into ’“table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '”‘"’“' LINES ”‘TERMINATED BY "’“'\n'”‘" IGNORE 1 LINES

The quotes like “ ‘ ’ ” in the above will be interpreted by bash. The quotes like " ' will end up in the resulting variable.

If I give the same treatment to the earlier example, it looks like this:

echo I like to use "double quotes" sometimes

Dilatory answered 17/8, 2015 at 17:35 Comment(1)
a subtlety of my second echo example, that I've not bothered to explain, is that here I'm actually giving echo three separate arguments, because the strings aren't touching. but the echo command prints all three, separated by spaces, so it sort of does what you'd expect. The difference is, if you type echo a b c it will output a b c, whereas if you type echo 'a b c' it will print a b c.Dilatory
C
34

Store the double quote character in a variable:

dqt='"'
echo "Double quotes ${dqt}X${dqt} inside a double quoted string"

Output:

Double quotes "X" inside a double quoted string
Crimson answered 14/11, 2017 at 5:45 Comment(2)
Bash truly is the worst languageShelving
@12oclocker, your answer is foolproof :D! specially when using with "sed" command it saved my day!Assentor
C
20

Check out printf...

#!/bin/bash
mystr="say \"hi\""

Without using printf

echo -e $mystr

Output: say "hi"

Using printf

echo -e $(printf '%q' $mystr)

Output: say \"hi\"

Cochlea answered 30/10, 2012 at 16:10 Comment(3)
Note that printf escapes more characters as well, such as ', ( and )Edytheee
printf %q generates strings ready for eval, not formatted for echo -e.Luckless
There is no reason to wrap the printf with a useless use of echo. Both your examples have broken quoting. The proper fix is to double-quote the variable.Synchrotron
R
12

Make use of $"string".

In this example, it would be,

dbload=$"load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"

Note (from the man page):

A double-quoted string preceded by a dollar sign ($"string") will cause the string to be translated according to the current locale. If the current locale is C or POSIX, the dollar sign is ignored. If the string is translated and replaced, the replacement is double-quoted.

Rocker answered 12/1, 2017 at 16:1 Comment(1)
Nice, didn't know that one.Serried
M
1

For use with variables that might contain spaces in you Bash script, use triple quotes inside the main quote, e.g.:

[ "$(date -r """$touchfile""" +%Y%m%d)" -eq "$(date +%Y%m%d)" ]
Moreover answered 6/2, 2022 at 3:35 Comment(2)
Triple quotes have no special meaning in bash: two of the quotes cancel each other out, leaving only the third; making the behavior 100% identical to just using only one quote. ($( ) creates a new quoting context, so you don't need to escape double quotes inside it at all in the first place; it's only backticks that have a problem there).Luckless
Try it yourself: [ "$(date -r "$touchfile" +%Y%m%d)" -eq "$(date +%Y%m%d)" ] works exactly the same way as the code suggested in this answer.Luckless
I
0

How about use echo.

For example,

x=$(echo \"a b c\")

To use the variable,

echo $x && ls "$x"

The reason I prefer echo rather than printf is that it's more straightforward.

Ideal answered 22/4, 2023 at 17:10 Comment(0)
H
-10

Add "\" before double quote to escape it, instead of \

#! /bin/csh -f

set dbtable = balabala

set dbload = "load data local infile "\""'gfpoint.csv'"\"" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"\""' LINES TERMINATED BY "\""'\n'"\"" IGNORE 1 LINES"

echo $dbload
# load data local infile "'gfpoint.csv'" into table balabala FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "''" IGNORE 1 LINES
Hoof answered 16/2, 2017 at 8:17 Comment(1)
Downvote: Why are you posting a csh answer to a bash question? The two are completely distinct and incompatible.Synchrotron

© 2022 - 2025 — McMap. All rights reserved.