嵌套参数扩展:为什么$ {foo%“ $ bar”}合法,但$ {$ bar}不合法?

时间:2019-11-17 18:26:48

标签: bash shell

我将从两个激励性的示例开始,为问题提供适当的上下文,然后提出问题。首先考虑以下示例:

$ ext=.mp3
$ fname=file.mp3
$ echo ${fname%"$ext"}
file

很明显,在解析${fname%"$ext"}时,bash首先将$ext扩展为.mp3,然后将${fname%.mp3}扩展为file —最后一步是从%扩展的定义。让我困惑的是$ext ...

的扩展

尤其是,让我们将上面的示例与以下示例进行比较:

$ a=value
$ b=a
$ echo ${$b}
-bash: ${$b}: bad substitution

当然,我知道我可以在这里使用“间接扩展”来实现我想要的:

$ echo ${!b}
value

但这与我的问题无关。我想了解特定的bash评估和解析规则,这些规则和解释规则解释了为何${$b}失败而${fname%"$ext"}成功的原因。

我在man bash中找到的唯一相关段落是:

  

扩展顺序为:大括号扩展;波浪号扩展,参数和变量扩展,算术扩展和命令替换(以从左到右的方式完成);分词和路径名扩展。

但是我没有看到这些规则如何产生不同的行为。

我想看到一个解释,它解释了两个示例的评估过程的每个步骤以及每个步骤所依据的规则。

1 个答案:

答案 0 :(得分:5)

如果您在bash manual中查找${parameter%word}扩展,则会发现parameterword的区别。 word路径名扩展的约束,而parameter受此约束。

${parameter%word}
${parameter%%word}
     

删除匹配的后缀模式。 word被展开以产生一个   模式,就像在路径名扩展中一样。如果该模式与   parameter扩展值的尾部,然后是结果   展开的是parameter的展开值中最短的   匹配模式(%情况)或最长匹配模式(   %%情况)已删除。如果参数为@*,则删除模式   依次将操作应用于每个位置参数,并且   扩展是结果列表。如果parameter是数组变量   下标为@*的样式删除操作将应用于   数组的每个成员轮流使用,展开是结果   列表。

这似乎可以解释它。但事实并非如此。 路径名扩展仅表示与*?等类似的通配符和模式匹配。它不包括变量扩展。

关键是要阅读。有适用于上述情况的序言:

  

在以下每种情况下, word都将发生波浪号扩展,参数扩展,命令替换和算术扩展。

总体上,word受这些扩展的所有 约束。该问题的关键:$ext通过递归参数扩展扩展。

我说“递归”是因为它实际上可以任意深度嵌套。发挥作用:

$ echo ${fname%.mp3}
file
$ echo ${fname%"$ext"}
file
$ echo ${fname%"${ext%"$empty"}"}
file
$ echo ${fname%"${ext%"${empty%""}"}"}
file