负参数在参数扩展中如何在extglob中工作

时间:2017-05-29 12:03:47

标签: bash parameter-expansion extglob

问题

的行为
!(pattern-list)

不能像我在参数扩展中使用的那样工作,特别是

${parameter/pattern/string}

输入

a="1 2 3 4 5 6 7 8 9 10"

测试用例

$ printf "%s\n" "${a/!([0-9])/}"
[blank]
#expected 12 3 4 5 6 7 8 9 10

$ printf "%s\n" "${a/!(2)/}"
[blank]
#expected  2 3 4 5 6 7 8 9 10

$ printf "%s\n" "${a/!(*2*)/}"
2 3 4 5 6 7 8 9 10
#Produces the behaviour expected in previous one, not sure why though

$ printf "%s\n" "${a/!(*2*)/,}"
,2 3 4 5 6 7 8 9 10
#Expected after previous worked

$ printf "%s\n" "${a//!(*2*)/}"
2
#Expected again previous worked

$ printf "%s\n" "${a//!(*2*)/,}"
,,2,
#Why are there 3 commas???

功能

GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)

注释

这些都是非常基本的例子,所以如果可以在答案中包含更复杂的例子和解释,那么请做。

需要更多信息或示例,请在评论中告诉我。

已经查看了How does extglob work with shell parameter expansion?,甚至评论了这个特定问题的问题,所以请不要将其标记为傻瓜。

1 个答案:

答案 0 :(得分:4)

表单${parameter/pattern/string}(其中pattern不以/开头)的参数展开通过查找变量值{{1}中最左边最长的子字符串来工作匹配模式parameter并将其替换为pattern。换句话说,string被分解为三个部分$parameterprefixmatch,以便

  1. suffix
  2. $parameter == "${prefix}${match}${suffix}"是最短的字符串,可以满足其他要求(即匹配,如果可能的话,发生在最左边的位置)
  3. $prefix匹配$match并尽可能长
  4. pattern$prefix和/或$match中的任何一个都可以为空
  5. $suffix的结果为${parameter/pattern/string}

    对于这种类型的参数扩展的全局替换形式("${prefix}string${suffix}"),对${parameter//pattern/string}部分递归地执行相同的过程,但是a zero-length match is handled as a special case(为了防止无限递归) ):

    • 如果suffix

      "${prefix}${match}" != ""

      其他"${parameter//pattern/string}" = "${prefix}string${suffix//pattern/string}"

      suffix=${parameter:1}

    现在让我们分别分析案例:

    • "${parameter//pattern/string}" = "string${parameter:0:1}${suffix}//pattern/string}" 。的确,' 1 2 3 4 5 6 7 8 9 10' 不是由单个数字组成的字符串,因此它与模式"${a/!([0-9])/}" --> prefix='' match='1 2 3 4 5 6 7 8 9 10' suffix=''匹配。因此,扩张的空洞结果。

    • !([0-9])。与上述类似,' 1 2 3 4 5 6 7 8 9 10' 不是由单个字符' 2'组成的字符串,因此它与模式"${a/!(2)/}" --> prefix='' match='1 2 3 4 5 6 7 8 9 10' suffix=''匹配。因此,扩张的空洞结果。

    • !(2)。子串' 1' 匹配模式"${a/!(*2*)/}" --> prefix='' match='1 ' suffix='2 3 4 5 6 7 8 9 10',因此它与模式*2*匹配。

    • !(*2*)。这里没有惊喜,所以不需要详细说明。

    • "${a/!(*2*)/,}"。这里没有惊喜,所以不需要详细说明。

    • "${a//!(*2*)/}"。然后"${a//!(*2*)/,}" --> prefix='' match='1 ' suffix='2 3 4 5 6 7 8 9 10'扩展为${suffix//!(*2*)/,},如下所示。 ",2,"开头的空字符串与模式suffix匹配,在结果中生成一个额外的逗号。由于触发了零长度匹配特殊情况(如上所述),强制使用!(*2*)的第一个字符,留下suffix,其整体与' 3 4 5 6 7 8 9 10'模式匹配,被替换为我们在扩展的最终结果中看到的最后一个逗号。