负匹配在参数扩展中extglob是如何工作的
How does negative matching work in extglob in parameter expansion
问题
的行为
!(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)
备注
这些都是非常基本的例子,所以如果可以在答案中包含更复杂的例子和解释,那么请这样做。
需要任何更多信息或示例,请在评论中告诉我。
已经看过 ,甚至评论了那个特定问题的问题所在,所以请不要标记为欺骗。
${parameter/pattern/string}
形式的参数扩展(其中 pattern
不以 /
开头)通过查找变量值中最左边最长的子字符串来工作 parameter
匹配模式 pattern
并将其替换为 string
。换句话说,$parameter
被分解为 prefix
、match
和 suffix
三部分,使得
$parameter == "${prefix}${match}${suffix}"
$prefix
是能够满足其他要求的最短字符串(即匹配,如果可能的话,出现在最左边的位置)
$match
匹配 pattern
并且尽可能长
$prefix
、$match
、and/or、$suffix
中任意一个都可以为空
而${parameter/pattern/string}
的结果是"${prefix}string${suffix}"
。
对于此类参数展开的全局替换形式(${parameter//pattern/string}
),对suffix
部分递归执行相同的过程,但是a zero-length match is handled as a special case(为了防止无限递归):
如果"${prefix}${match}" != ""
"${parameter//pattern/string}" = "${prefix}string${suffix//pattern/string}"
其他suffix=${parameter:1}
和
"${parameter//pattern/string}" = "string${parameter:0:1}${suffix}//pattern/string}"
下面我们逐个分析案例:
"${a/!([0-9])/}" --> prefix='' match='1 2 3 4 5 6 7 8 9 10' suffix=''
。事实上,'1 2 3 4 5 6 7 8 9 10' 不是 由单个数字组成的字符串,因此它匹配模式 !([0-9])
。因此展开的空结果。
"${a/!(2)/}" --> prefix='' match='1 2 3 4 5 6 7 8 9 10' suffix=''
。与上面类似,'1 2 3 4 5 6 7 8 9 10' 不是 由单个字符 '2' 组成的字符串,因此它匹配模式 !(2)
.因此展开的空结果。
"${a/!(*2*)/}" --> prefix='' match='1 ' suffix='2 3 4 5 6 7 8 9 10'
。子字符串“1”不匹配模式*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'
,它完全匹配 !(*2*)
模式并且替换为我们在展开的最终结果中看到的最后一个逗号。
问题
的行为!(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)
备注
这些都是非常基本的例子,所以如果可以在答案中包含更复杂的例子和解释,那么请这样做。
需要任何更多信息或示例,请在评论中告诉我。
已经看过
${parameter/pattern/string}
形式的参数扩展(其中 pattern
不以 /
开头)通过查找变量值中最左边最长的子字符串来工作 parameter
匹配模式 pattern
并将其替换为 string
。换句话说,$parameter
被分解为 prefix
、match
和 suffix
三部分,使得
$parameter == "${prefix}${match}${suffix}"
$prefix
是能够满足其他要求的最短字符串(即匹配,如果可能的话,出现在最左边的位置)$match
匹配pattern
并且尽可能长$prefix
、$match
、and/or、$suffix
中任意一个都可以为空
而${parameter/pattern/string}
的结果是"${prefix}string${suffix}"
。
对于此类参数展开的全局替换形式(${parameter//pattern/string}
),对suffix
部分递归执行相同的过程,但是a zero-length match is handled as a special case(为了防止无限递归):
如果
"${prefix}${match}" != ""
"${parameter//pattern/string}" = "${prefix}string${suffix//pattern/string}"
其他
suffix=${parameter:1}
和"${parameter//pattern/string}" = "string${parameter:0:1}${suffix}//pattern/string}"
下面我们逐个分析案例:
"${a/!([0-9])/}" --> prefix='' match='1 2 3 4 5 6 7 8 9 10' suffix=''
。事实上,'1 2 3 4 5 6 7 8 9 10' 不是 由单个数字组成的字符串,因此它匹配模式!([0-9])
。因此展开的空结果。"${a/!(2)/}" --> prefix='' match='1 2 3 4 5 6 7 8 9 10' suffix=''
。与上面类似,'1 2 3 4 5 6 7 8 9 10' 不是 由单个字符 '2' 组成的字符串,因此它匹配模式!(2)
.因此展开的空结果。"${a/!(*2*)/}" --> prefix='' match='1 ' suffix='2 3 4 5 6 7 8 9 10'
。子字符串“1”不匹配模式*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'
,它完全匹配!(*2*)
模式并且替换为我们在展开的最终结果中看到的最后一个逗号。