如何在双引号内转义双引号?


286

如何在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 '\"'用双引号正确逃生。我不能对变量使用单引号,因为我想使用variable $dbtable




2
@kenorb看起来不像是那个问题的重复……
Mark


@Daenyth这不是您希望最终用户可以访问的命令类型。批量加载脚本通常由受信任的用户(例如系统管理员或开发人员)在服务器运行。是的,如果最终用户控制的值$dbtable,则存在风险。但是,这将是非常罕见的,因为最终用户通常不将SSH SSH到计算机中以加载其数据。
jpmc26

Answers:


285

使用反斜杠:

echo "\""     # Prints one " character.

9
不工作 x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;给断了而工作... [ -f "$(which $x)" ]; ...还是... [ -f $(which "$x") ]; ...很好。当$x或结果$(which "$x")给出带有空格或其他特殊字符的任何内容时,就会出现问题。解决方法是使用变量保存的结果which,但是bash确实不能转义引号,或者我做错了吗?
吕克(Luc)2015年

我正在尝试将以下内容grep -oh "\"\""$counter"\""\w*" 用作bash语法的一部分,其中in $counter是变量。它不喜欢任何想法
Jay D

82

在shell中转义引号的简单示例:

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

通过完成已经打开的一个('),放置转义的一个(\'),然后打开另一个(')来完成此操作。

或者:

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

通过完成已经打开的一个('),在另一个引号("'")中放置一个引号,然后打开另一个('),可以完成此操作。

更多示例:将单引号引起来的单引号转义


1
我尝试了sh -c“ echo'{” key“:” value“}'”甚至什至sh -c“ echo'{''”''key''“'':''” value“”' '}'“,以将单词key和value括在双引号中,但是在两种情况下,我都得到了{key:value}
Igor Yagolnitser

1
对于双引号来说,这似乎不必要地复杂:echo "abc\"abc"足以abc"abc像彼得回答中那样产生。
divenex '18

2
确实在这个简单示例中,但是在嵌套引号的复杂情况下,有必要这样做,而@kenorb的示例帮助我弄清楚了如何处理这些情况。
prosoitos

63

我不知道为什么这个老问题今天在Bash标签列表中突然出现,但是为了以防将来的研究人员注意,您可以通过使用需要回显的字符的ASCII码来避免转义。

例:

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

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

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

对于变量分配,这是等效的:

 $ a=$'This is \x22text\x22'
 $ echo "$a"
 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
+1是因为它解决了向〜/ .profile中添加PS1变量的问题 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 ) '' >> ~/.profile
Yassine ElBadaoui

1
这就是答案!先生,我爱你。
米格尔·罗哈斯·科尔特斯

28

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'' " IGNORE 1 LINES' ' ' ' ' ' ' ' '

上面的诸如“''”的引号将由bash解释。像这样的引号" '将最终出现在结果变量中。

如果我对前面的示例进行相同的处理,则如下所示:

$ echoI like to use"double quotes"sometimes


4
哎呀...这很丑。
魔术章鱼缸

17

签出printf ...

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

不使用printf

echo -e $mystr

输出:说“嗨”

使用printf

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

输出:说“嗨”


2
需要注意的是printf逃脱多个字符为好,如'()
大卫Pärsson

printf %q生成准备用于eval格式化的字符串echo -e
查尔斯·达菲

2
没有理由来包装printf一个无用的使用echo。您的两个示例都引用不完整。正确的解决方法是将变量双引号。
人间

15

将双引号字符存储为变量:

dqt ='“'
回声“双引号字符串内的双引号$ {dqt} X $ {dqt}”

输出:

双引号字符串中的双引号“ X”

39
Bash确实是最糟糕的语言
Andy Ray

@ 12oclocker,您的回答是万无一失的:D!特别是当与“ sed”命令一起使用时,它挽救了我的一天!
Artanis Zeratul

11

利用$“ string”。

在这个例子中,

dbload = $“将数据本地文件\”'gfpoint.csv'\“加载到表$ dbtable中','封闭的'\''行以\”'\ n'\“终止的行忽略1行

注意(从手册页开始):

用双引号引起来的字符串前面带有美元符号($“ string”),将导致该字符串根据当前语言环境进行翻译。如果当前语言环境为C或POSIX,则忽略美元符号。如果字符串被翻译和替换,替换将被双引号引起来。


3
很好,不知道那个。
David Kierans '18

-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

6
Downvote:您为什么要发布问题的csh答案bash?两者是完全不同且不兼容的。
人间
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.