【问题标题】:Bash parameter expansion ${parameter/pattern/string} with quotes带引号的 Bash 参数扩展 ${parameter/pattern/string}
【发布时间】:2015-01-16 04:05:26
【问题描述】:

这是我在 SO 上的第一篇文章(虽然潜伏了很长时间),所以我提前为我肯定要犯的众多“失礼”和其他错误道歉。

我已经在谷歌上找了一段时间了,现在试图找到在双引号内的参数扩展内如何解析引号的答案,似乎我要么有错误的关键字,要么是一个非常扭曲的尝试尝试这个。

例如,如果我有一个像It's a complicated string 这样的字符串,我想使用bash 的参数扩展${parameter/pattern/string} 将该字符串转换为序列It'\''s a complicated string我知道我可以使用许多其他内置或外部工具之一来实现该结果(我自己非常喜欢 sed),但这个问题实际上是关于了解 bash 的想法,以便我可以把我的自己的心来放松。

Bash's reference 在描述其“模式”时似乎没有具体说明在这种特殊情况下会发生什么,而the closest question on SO 在我的情况下似乎不起作用:

$ echo "$str"
It's a complicated string
$ echo "${str//'/'\''}"
> ^C
$ echo "${str//'/'\''}"
> ^C
$ echo "${str//\'/'\''}"
> ^C
$ echo "${str//\'/\'\''}"
> ^C
$ echo "${str//\'/\'\'\'}"
It\'\'\'s a complicated string
$ echo "${str//\\'/\'\'\'}"
It's a complicated string
$ echo "${str//\\'/\\'\'\'}"
It's a complicated string
$ echo "${str//\\'/\\'\\'\'}"
It's a complicated string
$ echo "${str//\\'/\\'\\'\\'}"
It's a complicated string
$ echo "${str//\\\'/\\'\\'\\'}"
> ^C
$ echo "${str//\\\'/\\\'\\'\\'}"
It's a complicated string
$ echo "${str//\\\'/\\\'\\\'\\'}"
> ^C
$ echo "${str//\\\'/\\\'\\\'\\\'}"
It's a complicated string

> ^C 行表示引号未正确解析,系统提示我输入更多内容,我每次使用 Ctrl-C 时都无情地拒绝。)

请大家解释一下 bash 究竟是如何看待这个问题的?我真的希望这只是我们之间的沟通问题,我有点喜欢他。 :)

编辑:

对于那些想知道的人,Etan Reisner 的回答很有效:

$ q=\'
$ echo "${str//\'/$q\'$q}"
It'\''s a complicated string

至于斯普特尼克的回答,我更疑惑了:

$ echo "${str//\047/\047\\\047\047}"
It's a complicated string
$ echo "${str//\047/\047\047}"
It's a complicated string
$ echo "${str//\'/\047\'\047}"
It\047\'\047s a complicated string
$ echo "${str//\'/\047\047\047}"
It\047\047\047s a complicated string
$ echo "${str//'/\047\047\047}"
> ^C
$ echo "${str//\047/\047\047\047}"
It's a complicated string
$ echo "${str//\047/\047\\\047\047}"
It's a complicated string

EDIT2:

显然,这是一个至少影响 bash 4.1 和 4.2 的错误,并已在 bash 4.3 中修复。因此,从上面的测试中没有什么可以理解的。

【问题讨论】:

  • 使用\\',对于 bash,你有一个反斜杠并且你正在打开一个单引号(而 Bash 正在等待你关闭它——你可以通过按 Ctrl-C 来取消它)。尝试一些有趣的事情:不要按 Ctrl-C,而是输入 I love bananas'}" 并享受。
  • @gniourf_gniourf 我可以理解${parameter/pattern/string} 的“模式”部分中的行为,但在“字符串”部分中,所有字符都应该是文字吗?
  • 一个更好的问题是,为什么要创建这样的字符串?原件是一个包含单引号的完全有效的字符串;您的编辑似乎试图在字符串中添加带引号的单引号(我可能会添加不正确),以尝试在字符串中包含 bash 语法。
  • @EtanReisner 来自手册:模式被扩展以产生一个模式,就像在文件名扩展中一样。所以这里没有惊喜。

标签: bash replace quotes


【解决方案1】:

以下作品(带或不带双引号):

echo "${str//\'/\'\\\'\'}"

每个单引号都用反斜杠转义,以防止它开始单引号字符串。文字反斜杠也在替换模式中被转义。


bash 4.3 会话直接复制和粘贴:

$ str="It's a complicated string"
$ echo "${str//\'/\'\\\'\'}"
It'\''s a complicated string
$ echo ${str//\'/\'\\\'\'}
It'\''s a complicated string

bash 3.2 中的输出是相同的。

【讨论】:

  • 带有不会生成所需输出的引号。如果没有引号,它会这样做,但这可能不再安全了。
  • Etan 是对的:当我运行它时,我得到了 It\'\\'\'s a complicated string
  • 真的吗?我得到了我认为在 3.2 和 4.3 中想要的输出。
  • @chepner Strange...我在 bash 4.2 上,无论是否使用 posix 模式,我都会得到错误的输出。回家后我会尝试更新的 bash 版本。也许我刚刚发现了一个只影响 4.2 的“功能”?
  • 4.1 显示的输出与您在上面显示的相同。这可能是 4.0(或 4.1?)中引入的错误,已在 4.3 中修复。
【解决方案2】:

我无法解释 bash 到底在做什么,但与 @sputnick 类似,我的建议是不要玩游戏。

q=\'
echo "${str//\'/$q\'$q}"

【讨论】:

  • 这确实有效(我编辑了我的问题以反映这一点),但在解析我的初始命令行时我仍然不理解 bash 的奇怪行为。
【解决方案3】:

与其尝试奇怪的转义游戏,不如尝试使用ascii 表示单引号:\047

man 7 ascii

【讨论】:

  • 我的 bash 似乎看不出 ` and the escape sequence \047` 之间有任何区别(请参阅我编辑的答案)。
猜你喜欢
  • 2014-06-17
  • 1970-01-01
  • 2022-06-29
  • 1970-01-01
  • 1970-01-01
  • 2016-05-14
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
相关资源
最近更新 更多