当前位置:  开发笔记 > 编程语言 > 正文

如何在单引号字符串中转义单引号?

如何解决《如何在单引号字符串中转义单引号?》经验,为你挑选了12个好方法。

比方说,你有一个alias像bash 一样:

alias rxvt='urxvt'

哪个工作正常.

然而:

alias rxvt='urxvt -fg '#111111' -bg '#111111''

不会起作用,也不会:

alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''

那么,一旦转义了引号,你最终如何在字符串中匹配开头和结尾的引号?

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''

看起来很笨拙虽然如果你允许这样连接它们就会代表相同的字符串.



1> liori..:

如果你真的想在最外层使用单引号,请记住你可以粘合两种报价.例:

 alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
 #                     ^^^^^       ^^^^^     ^^^^^       ^^^^
 #                     12345       12345     12345       1234

解释如何'"'"'被解释为':

    ' 结束使用单引号的第一个引用.

    " 使用双引号开始第二次引用.

    ' 引用字符.

    " 结束第二次报价,使用双引号.

    ' 使用单引号启动第三个引号.

如果不在(1)和(2)之间,或者在(4)和(5)之间放置任何空格,shell将把该字符串解释为一个长字.


我认为`'\''在大多数情况下比''''''更具可读性.实际上,前者在单引号字符串中几乎总是明显不同,因此只是将它在语义上映射到"它是一个转义引号"的意思,就像用双引号字符串中的`\"`一样虽然后者混合成一行报价单,但在许多情况下需要仔细检查才能正确区分.
我的解释:bash隐式连接不同引用的字符串表达式.
liori:恕我直言http://stackoverflow.com/a/16605140/149221更优雅:-).
`alias splitpath ='echo $ PATH | awk -F:'''''{print"PATH设置为"} {for(i = 1; i <= NF; i ++){print"["i"]",$ i}}'"'" `当别名字符串中有单引号和双引号时,它可以工作!
为我工作,双逃脱单引号的例子:`alias serve_this_dir ='ruby -rrack -e"包括Rack; Handler :: Thin.run Builder.new {run Directory.new'"''''''''} "'`

2> Adrian Pronk..:

我总是用序列替换每个嵌入的单引号:( '\''即:引用反斜杠引用引号),它关闭字符串,附加转义的单引号并重新打开字符串.


我经常在我的Perl脚本中添加一个"quotify"函数来为我做这个.步骤将是:

s/'/'\\''/g    # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.

这几乎照顾了所有情况.

引入evalshell脚本时,生活会变得更有趣.你基本上必须再次重新报价!

例如,创建一个名为quotify的Perl脚本,其中包含以上语句:

#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];

然后用它来生成一个正确引用的字符串:

$ quotify
urxvt -fg '#111111' -bg '#111111'

结果:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

然后可以将其复制/粘贴到alias命令中:

alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

(如果需要将命令插入eval,请再次运行quotify:

 $ quotify
 alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

结果:

'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

可以复制/粘贴到eval中:

eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''


第一段本身就是我要找的答案.
这就是bash所做的,输入`set -x`和`echo'这里是一个字符串"`你会看到bash在这里'echo'执行`echo'.(`set + x`返回正常行为)
@nicerobot:我添加了一个示例,表明:1)我不会尝试在相同类型的引号中转义引号,2)也不会在其他引号中转义,3)Perl用于自动生成有效的过程bash字符串包含嵌入的引号

3> mj41..:

由于Bash 2.04语法$'string'(而不仅仅是'string';警告:不要混淆$('string'))是另一种引用机制,它允许ANSI C类转义序列并扩展到单引号版本.

简单的例子:

  $> echo $'aa\'bb'
  aa'bb

  $> alias myvar=$'aa\'bb'
  $> alias myvar
  alias myvar='aa'\''bb'

在你的情况下:

$> alias rxvt=$'urxvt -fg \'#111111\' -bg \'#111111\''
$> alias rxvt
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

常见的转义序列按预期工作:

\'     single quote
\"     double quote
\\     backslash
\n     new line
\t     horizontal tab
\r     carriage return

以下是man bash(版本4.4)的复制+粘贴相关文档:

$'string'形式的单词是专门处理的.单词扩展为字符串,替换为ANSI C标准指定的反斜杠转义字符.反斜杠转义序列(如果存在)按如下方式解码:

    \a     alert (bell)
    \b     backspace
    \e
    \E     an escape character
    \f     form feed
    \n     new line
    \r     carriage return
    \t     horizontal tab
    \v     vertical tab
    \\     backslash
    \'     single quote
    \"     double quote
    \?     question mark
    \nnn   the eight-bit character whose value is the octal 
           value nnn (one to three digits)
    \xHH   the eight-bit character whose value is the hexadecimal
           value HH (one or two hex digits)
    \uHHHH the Unicode (ISO/IEC 10646) character whose value is 
           the hexadecimal value HHHH (one to four hex digits)
    \UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value 
               is the hexadecimal value HHHHHHHH (one to eight 
               hex digits)
    \cx    a control-x character

扩展结果是单引号,好像美元符号不存在一样.


有关更多详细信息,请参阅bash-hackers.org wiki上的引用和转义:ANSI C类似字符串.另请注意,"Bash Changes"文件(此处概述)提到了很多与$'string'引用机制相关的更改和错误修复.

根据unix.stackexchange.com 如何使用特殊字符作为普通字符?它应该在bash,zsh,mksh,ksh93和FreeBSD以及busybox sh中工作(有一些变化).


在我的机器上`> echo $ BASH_VERSION``4.2.47(1)-release``> echo $'foo \'b!ar'``foo'b!ar`

4> Steve B...:

我没有看到他博客上的条目(链接请参阅?)但是根据gnu参考手册:

用单引号(''')括起字符可以保留引号中每个字符的字面值.单引号之间可能不会出现单引号,即使前面有反斜杠也是如此.

所以bash不会理解:

alias x='y \'z '

但是,如果用双引号括起来,你可以这样做:

alias x="echo \'y "
> x
> 'y


马修,问题是关于在单引号内转义单引号.这个答案要求用户改变他们的行为,如果你有使用双引号的障碍(正如问题标题所示),这个答案将无济于事.它虽然很有用(虽然很明显),因此值得推特,但接受的答案解决了Op所提出的确切问题.
这是问题的实际答案.虽然接受的答案可能提供解决方案,但它在技术上回答了一个未被问到的问题.

5> Mikhail at Y..:

我可以确认'\''在单引号字符串中使用单引号确实可以在Bash中使用,并且它可以用与线程早期的"粘合"参数相同的方式来解释.假设我们有一个带引号的字符串:( 'A '\''B'\'' C'这里的所有引号都是单引号).如果传递给echo,则打印以下内容:A 'B' C.在每个'\''第一个引号中关闭当前单引号字符串,下面\'将单引号粘合到前一个字符串(\'是一种指定单引号而不启动引用字符串的方式),最后一个引号打开另一个单引号字符串.


这是误导性的,这种语法'\''不会在单个引用的字符串中"内部".在此语句'A'\''B'\''C'中,您将连接5\escape和单引号字符串

6> 小智..:

两个版本都可以正常工作,可以通过使用转义的单引号字符(\')进行连接,也可以通过将单引号字符括在双引号("'")中进行连接.

该问题的作者没有注意到在他最后一次逃避尝试结束时有一个额外的单引号('):

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
           ?         ???|       ????     ????       ????
           ??STRING???????STRIN??????STR??????STRIN?????
                      ??         ??       ??         ???
                      ??         ??       ??         ???
                      ??????????????????????????????????
                          All escaped single quotes    ?
                                                       ?
                                                       ?

正如您在上一篇优秀的ASCII/Unicode艺术作品中所看到的,最后一个转义的单引号(\')后跟一个不必要的单引号(').使用类似于Notepad ++中的语法高亮显示器可以证明非常有用.

对于另一个例子,如下所示,情况也是如此:

alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'

这两个漂亮的别名实例以非常复杂和混淆的方式显示文件如何排列.也就是说,从包含大量行的文件中,只能在前一行的内容之间使用逗号和空格.为了理解之前的评论,以下是一个例子:

$ cat Little_Commas.TXT
201737194
201802699
201835214

$ rc Little_Commas.TXT
201737194, 201802699, 201835214


敬请为ASCII表插图:)

7> kenorb..:

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

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

这是通过完成已经打开的one('),放置一个(\'),然后打开另一个(')来完成的.此语法适用于所有命令.这与第一个答案非常相似.



8> nicerobot..:

我并没有专门解决引用问题,因为有时,考虑替代方法是合理的.

rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }

您可以将其称为:

rxvt 123456 654321

这个想法是你现在可以别名,而不用担心引号:

alias rxvt='rxvt 123456 654321'

或者,如果#由于某种原因需要包括所有呼叫:

rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }

您可以将其称为:

rxvt '#123456' '#654321'

那么,当然,别名是:

alias rxvt="rxvt '#123456' '#654321'"

(哎呀,我想我确实解决了引用:)



9> Rob Jens..:

我只是使用shell代码...例如\x27\\x22适用.没有麻烦,真的.



10> Nerrve..:

由于不能在单引号字符串中放置单引号,因此最简单且最易读的选项是使用HEREDOC字符串

command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)

alias rxvt=$command

在上面的代码中,HEREDOC被发送到cat命令,并通过命令替换表示法将其输出分配给变量$(..)

需要在HEREDOC周围添加单引号,因为它位于a $()



11> teknopaul..:

恕我直言,真正的答案是你无法在单引号字符串中转义单引号.

不可能.

如果我们假设我们正在使用bash.

从bash手册...

Enclosing characters in single quotes preserves the literal value of each
character within the quotes.  A single quote may not occur
between single quotes, even when preceded by a backslash.

你需要使用其他一个字符串转义机制"或\

关于alias使用单引号的要求没有什么神奇之处.

以下两个都在bash中工作.

alias rxvt="urxvt -fg '#111111' -bg '#111111'"
alias rxvt=urxvt\ -fg\ \'#111111\'\ -bg\ \'#111111\'

后者正在使用\来逃避空间角色.

#111111也没有什么神奇之处需要单引号.

以下选项与其他两个选项的结果相同,因为rxvt别名按预期工作.

alias rxvt='urxvt -fg "#111111" -bg "#111111"'
alias rxvt="urxvt -fg \"#111111\" -bg \"#111111\""

你也可以直接逃避麻烦的#

alias rxvt="urxvt -fg \#111111 -bg \#111111"



12> Kyle Rose..:

大多数答案都是针对您所询问的具体案例.有一种普遍的做法,我和一个朋友已经开发了允许任意的情况下,引用您需要引用通过shell扩展,例如,通过ssh的多层次的bash命令,su -c,bash -c,等,有一个核心的基本需要,在这里在本地bash中:

quote_args() {
    local sq="'"
    local dq='"'
    local space=""
    local arg
    for arg; do
        echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
        space=" "
    done
}

这正是它所说的:它单独引用每个参数(当然是在bash扩展之后):

$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'

对于一层扩展,它显而易见:

$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2

(注意,使用双引号$(quote_args ...)是将结果转换为单个参数所必需的bash -c.)并且它可以更普遍地用于通过多个扩展层正确引用:

$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2

上面的例子:

    shell - quote_args单独引用内部的每个参数,然后将结果输出组合成具有内部双引号的单个参数.

    shell-quotes bash,-c以及步骤1中已经引用过的结果,然后将结果与外部双引号组合成一个参数.

    将这个混乱作为参数发送到外部bash -c.

这就是简单的想法.你可以用这个来做一些非常复杂的事情,但你必须要小心评估的顺序以及引用哪些子串.例如,以下做错事(对于"错误"的某些定义):

$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure

在第一示例中,bash的立即膨胀quote_args cd /; pwd 1>&2成两个单独的命令,quote_args cd /并且pwd 1>&2,因此,CWD仍/tmp的时pwd被执行的命令.第二个例子说明了一个类似于globbing的问题.实际上,所有bash扩展都会出现同样的基本问题.这里的问题是命令替换不是函数调用:它实际上是在评估一个bash脚本并将其输出作为另一个bash脚本的一部分.

如果你试图简单地转义shell运算符,你就会失败,因为传递给bash -c它的结果字符串只是一系列单独引用的字符串,然后不会被解释为运算符,如果你回显字符串就很容易看到已经传递给bash:

$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'

这里的问题是你过度引用.您需要的是操作符不被引用作为封闭的输入bash -c,这意味着它们需要在$(quote_args ...)命令替换之外.

因此,在最一般意义上,您需要做的是在命令替换时单独引用命令的每个单词并不打算扩展,并且不对shell运算符应用任何额外的引用:

$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success

一旦你完成了这个,整个字符串是公平的游戏,以进一步引用任意级别的评估:

$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success

等等

这些例子可能看起来过于紧张,因为单词喜欢success,sbin并且pwd不需要被shell引用,但是在编写任意输入的脚本时要记住的关键点是你要引用你并不是绝对确定的所有内容.牛逼需要报价,因为你永远不知道什么时候,用户将在一个扔Robert'; rm -rf /.

为了更好地理解幕后的内容,您可以使用两个小助手函数:

debug_args() {
    for (( I=1; $I <= $#; I++ )); do
        echo -n "$I:<${!I}> " 1>&2
    done
    echo 1>&2
}

debug_args_and_run() {
    debug_args "$@"
    "$@"
}

在执行命令之前,它将枚举命令的每个参数:

$ debug_args_and_run echo a'"'b"'"c arg2
1: 2: 3: 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1: 2: 3: 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1: 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1: 2: 3: 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1: 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1: 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1: 2: 3: 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1: 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''> 
1: 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1: 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1: 2: 3: 
a"b'c arg2

推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有