【问题标题】:How can I escape a double quote inside double quotes?如何在双引号内转义双引号?
【发布时间】:2011-04-19 14:08:07
【问题描述】:

如何在 Bash 的双字符串中转义双引号?

例如,在我的 shell 脚本中

#!/bin/bash

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

我无法让带有双引号的ENCLOSED BY '\"' 正确转义。我的变量不能使用单引号,因为我想使用变量$dbtable

【问题讨论】:

标签: bash quotes


【解决方案1】:

请记住,您可以通过使用需要回显的字符的 ASCII 码来避免转义。

例子:

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

\x22 是双引号的 ASCII 码(十六进制),\x27 是单引号的 ASCII 码。同样,您可以回显任何字符。

我想如果我们尝试用反斜杠回显上面的字符串,我们将需要一个凌乱的两行反斜杠回显......:)

对于变量赋值,这是等价的:

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

# Output:
This is "text"

如果变量已由另一个程序设置,您仍然可以使用 sed 或类似工具应用双引号/单引号。

例子:

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.

【讨论】:

  • +1 因为它解决了将 PS1 变量添加到 ~/.profile echo 'export PS1='\[\033[00;31m\]${?##0}$([ $? -ne 0 ] &amp;&amp; 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 ] &amp;&amp; echo \x22$\x22 || echo \x22#\x22 ) '' &gt;&gt; ~/.profile 的问题
  • 这就是答案!我爱你先生。
【解决方案2】:

利用 $"string"。

在这个例子中,它会是,

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

注意(来自man page):

以美元符号 ($"string") 开头的双引号字符串将导致根据当前语言环境翻译该字符串。如果当前语言环境是 C 或 POSIX,则忽略美元符号。如果字符串被翻译和替换,替换是双引号。

【讨论】:

  • 不错,不知道那个。
【解决方案3】:

Bash 允许您将字符串相邻放置,它们最终会粘在一起。

所以这个:

echo "Hello"', world!'

生产

Hello, world!

诀窍是根据需要在单引号和双引号字符串之间交替。不幸的是,它很快变得非常混乱。例如:

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

生产

I like to use "double quotes" sometimes

在你的例子中,我会这样做:

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

产生以下输出:

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

很难看出这里发生了什么,但我可以使用 Unicode 引号对其进行注释。以下内容在 Bash 中不起作用——这只是为了说明:

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

上面的“‘’”这样的引号将被 bash 解释。像" ' 这样的引号最终会出现在结果变量中。

如果我对前面的例子进行同样的处理,它看起来像这样:

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

【讨论】:

    【解决方案4】:

    将双引号字符存储在变量中:

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

    输出:

    Double quotes "X" inside a double quoted string
    

    【讨论】:

    • Bash 确实是最糟糕的语言
    • @12oclocker,你的回答是万无一失的:D!特别是与“sed”命令一起使用时,它节省了我的时间!
    【解决方案5】:

    在双引号之前添加"\" 以将其转义,而不是\

    #! /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
    

    【讨论】:

    • 投反对票:您为什么要发布cshbash 问题的回答?两者完全不同,互不相容。
    【解决方案6】:

    一个在shell中转义引号的简单例子:

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

    完成一个已打开的 ('),放置转义的 (\'),然后打开另一个 (')。

    或者:

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

    通过完成已打开的一个 ('),在另一个引号 ("'") 中添加一个引号,然后打开另一个 (') 来完成。

    更多示例:Escaping single-quotes within single-quoted strings

    【讨论】:

    • 我试过 sh -c "echo '{"key":"value"}'" 甚至 sh -c "echo '{''"''key''"'':'' "''value''"''}'" 试图将单词 key 和 value 括在双引号中,但在这两种情况下我都得到了 {key:value}
    • 这对于双引号来说似乎是不必要的复杂:echo "abc\"abc" 足以产生 abc"abc 就像彼得的回答一样。
    • 在这个简单的例子中确实如此,但在嵌套引号的复杂情况下,可能有必要这样做,@kenorb 的例子帮助我弄清楚如何处理这些情况。
    【解决方案7】:

    查看 printf...

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

    不使用 printf

    echo -e $mystr
    

    输出:说“嗨”

    使用 printf

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

    输出:说“嗨”

    【讨论】:

    • 请注意printf 也会转义更多字符,例如'()
    • printf %qeval 生成准备好的字符串,而不是为echo -e 格式化。
    • 没有理由用useless use of echo 包裹printf。您的两个示例都引用了错误。正确的解决方法是对变量进行双引号。
    【解决方案8】:

    使用反斜杠:

    echo "\""     # Prints one " character.
    

    【讨论】:

    • 不工作。 x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi; 坏了,而 ... [ -f "$(which $x)" ]; ...... [ -f $(which "$x") ]; ... 工作得很好。当$x$(which "$x") 的结果给出带有空格或其他特殊字符的任何内容时,就会出现问题。一种解决方法是使用变量来保存 which 的结果,但是 bash 真的无法转义引号还是我做错了什么?
    • 我正在尝试使用以下 grep -oh "\"\""$counter"\""\w*" 作为 bash 语法的一部分,其中 $counter 是一个变量。它不喜欢任何想法
    • 您好,您的方法无效。请删除您的答案,因为它可能已经浪费了很多有用的时间。正确答案由@kenorb 发布,您的答案仅在终端调用时有效,但不适用于 bash 文件。您甚至在发布之前自己尝试过这个(可能是剪切粘贴解决方案):(?
    猜你喜欢
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    • 2015-09-06
    相关资源
    最近更新 更多