bash - 如何escape单引号中带单引号的字符串?

  显示原文与译文双语对照的内容

假设你有一个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'''

看起来有些笨拙,但如果允许这样连接的话,它代表相同的字符串。

时间:

我总是用序列替换每个嵌入的单引号: ''' ( 即:引号反引号引号引号) 关闭字符串,追加转义的单引号并重新打开字符串。 我经常在Perl脚本中创建一个"quotify"函数来为我做这个。 步骤如下:


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

这几乎可以处理所有情况。

当你将 eval 引入shell-scripts时,生活变得更加有趣。 你本质上必须重新做 re-quotify !

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


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

然后使用它生成一个correctly-quoted字符串:


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

结果:


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

然后可以复制/粘贴到别名命令中:


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'''''''''''''

我没有在他的博客( 链接请链接) 中看到这个条目,但根据 gnu参考手册:?

在单引号中封闭字符(''') 保留引号中每个字符的字面值。 单引号不能在单引号之间出现,即使在使用反斜杠前。

所以bash将不理解:

alias x='y 'z '

但是,如果你使用双引号包围,则可以执行以下操作:


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

对于 Bash,这应该可以:


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

来自 man bash:

表单 $'string'的字被特殊处理。 单词扩展到字符串,backslash-escaped字符替换为由 ANSI C 标准指定的字符。 反斜杠转义序列如果存在,则按如下方式解码:


  backslash
 ' single quote
 " double quote
 n new line
. . .

请参阅示例:


> echo $'aa'bb'
 aa'bb

请参见引号和转义: 在 bash-hackers.org 维基有关 details, ansic字符串.等

我可以确认使用 ''' 为single-quoted字符串内的一个单引号使用,它可以用与线程前面的"粘附"参数相同的方式解释。 假设我们有一个带引号的字符串: 'A'''B'''C' ( 这里所有的引号都是单引号) 。 如果传递给 echo,它将打印以下内容: A'B'C 。在每个 ''' 中,第一个引号关闭当前的single-quoted字符串,下面的' 将一个单引号粘附到前一个字符串( ' 是一种在不启动引号的情况下指定单引号的方法),最后一个引号打开另一个single-quoted字符串。

我没有明确地解决引号问题,因为有时候,考虑一种替代方法是合理的。


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'"

( 哎呀,我想我已经解决了引号:)

在给定示例中,只使用双引号而不是单引号作为外部转义机制:


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

这里方法适用于许多情况下,你只需要将固定字符串传递给命令: 通过一个 echo,用反斜杠如果necessary,刚检查主界面会如何解读double-quoted的字符串和转义 characters.

在本例中,你可以看到双引号足以保护字符串:


$ echo"urxvt -fg '#111111' -bg '#111111'"
urxvt -fg '#111111' -bg '#111111'

下面是对上面提到的一个真实答案的详细描述:

有时候我将使用ssh下载 rsync,必须用it中的'in TWICE来转义文件名 ! ( OMG ) 一次用于 bash,一次用于 ssh 。 交替引号的原理在这里工作。

例如假设我们想要获取: theroux的故事。。

  1. 首先,你将 Louis Theroux放在单引号中,用于 bash,并将双引号用于 ssh: ''"theroux"''
  2. 然后使用单引号来转义双引号'"'
  3. 使用双引号转义撇号"'"
  4. 然后使用单引号重复 #2, 以转义双引号'"'
  5. 然后用单引号将LA和双引号括起来,为ssh加上双引号: ''"la故事"''

注意你会得到这样的结果: !


rsync -ave ssh '"Louis Theroux"''"'"'"'"''"s LA Stories"'

对于一个'--来说,你的工作量太大了

两个版本正在处理,也可以进行串联与并置通过使用转义单引号字符( '),或者通过将单引号字符括在双引号("'") 。

问题的作者没有注意到在最后一次转义尝试的末尾有一个额外的单引号('):


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

就像你在前面的ASCII艺术中看到的,最后一次转义的单引号( '是一个不需要的单引号) 。 使用syntax-highlighter中的一个可以证明非常有用。

同样的情况也适用于以下例子:


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

...