带引号的 Bash 参数扩展 $parameter/pattern/string

Posted

技术标签:

【中文标题】带引号的 Bash 参数扩展 $parameter/pattern/string【英文标题】: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 来自手册:模式被扩展以产生一个模式,就像在文件名扩展中一样。所以这里没有惊喜。 【参考方案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` 之间有任何区别(请参阅我编辑的答案)。

以上是关于带引号的 Bash 参数扩展 $parameter/pattern/string的主要内容,如果未能解决你的问题,请参考以下文章

Linux Bash Shell学习笔记

在 Bash 中包含多个带引号的 args 的变量

Bash编程 命令行解析与扩展

如何将带引号的多字字符串替换为参数?

$var?中bash变量参数扩展中的问号是啥意思?

bash 正则表达式带引号?