协慌网

登录 贡献 社区

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

比方说,你有一个 bash alias如:

alias rxvt='urxvt'

哪个工作正常。

然而:

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

不会起作用,也不会:

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

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

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

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

答案

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

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

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

  1. '结束使用单引号的第一个引用。
  2. "使用双引号开始第二次引用。
  3. '引用的角色。
  4. "结束第二次报价,使用双引号。
  5. '使用单引号开始第三次引用。

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

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


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

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

这几乎照顾了所有情况。

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

例如,创建一个名为 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 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 中工作(有一些变化)。