通过命令替换在赋值中嵌套双引号

通过命令替换在赋值中嵌套双引号

堆栈溢出回答拥有 > 3.5K 票的人使用此单行代码来分配DIR当前 bash 脚本的目录:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

我对嵌套的双引号感到困惑。据我所知,以下片段是用双引号引起来的:

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

=... (即$( dirname和)右侧的所有其他内容)均未加引号。换句话说,我假设第二个、第四个和第六个"字符分别“关闭”第一个、第三个和第五个"字符。

我明白双引号的作用是什么"${BASH_SOURCE[0]}",但是另外两对双引号的目的是什么?

另一方面,如果(尽管得票率很高)上述代码片段不正确,那么实现其名义意图的正确方法是什么?

(经过名义意图pwd我的意思是:收集第一个-ing返回的值到cd返回的目录dirname "${BASH_SOURCE[0]}",并在子 shell 中执行 -ing cd,这样$PWD父 shell 的 保持不变)。

答案1

一旦进入$(...),引用就从头开始。

换句话说,"..."并且$(...)可以彼此之内。命令替换, $(...), 可以包含一个或多个完全的双引号字符串。另外,双引号字符串可以包含一个或多个完全的命令替换。 但是,它们并不交织。 因此,在命令替换内部开始的双引号字符串永远不会扩展到命令替换之外,反之亦然。

所以,考虑:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

里面的内里$(...)是:

dirname "${BASH_SOURCE[0]}"

上面${BASH_SOURCE[0]}是双引号。$(...)在确定是否${BASH_SOURCE[0]}是双引号时,任何外部的双引号或单引号都是无关紧要的。

外层$(...)包含:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

这里,表达式$( dirname "${BASH_SOURCE[0]}" )是用双引号引起来的。$(...)当考虑内部的内容时,外部外部的引号这一事实是无关紧要的。事实上,内部有引号$(...)也是无关紧要的。

以下是双引号的匹配方式:

在此输入图像描述

答案2

bash您的困惑与如何(以及一般的 shell)解析输入的问题不正确。在:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

首先,bash将赋值的右侧解析为一个长字符串,$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )因为双引号可以出现在里面双引号

之后,bash开始解析命令替换。由于左括号和右括号后面的所有字符都用于在命令替换中构造命令,因此您将得到:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

shell 继续解析该复合命令,将其分为两部分:

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • 密码

然后对 应用相同的解析规则cd "$( dirname "${BASH_SOURCE[0]}" )",但这一次,双引号不是多余的,而是有意义的。它们防止 的结果上的字段分割$( dirname "${BASH_SOURCE[0]}" ),以及${BASH_SOURCE[0]}(与最外面的双引号相反,将在变量赋值的 RHS 中不需要防止split+glob)。


该规则适用于所有 POSIX shell 中的命令替换。您可以阅读更多详细信息的谜题POSIX 规范的令牌识别部分

相关内容