我知道一个事实,它bash支持带有正则表达式的扩展glob,如支持@(foo|bar),*(foo)和?(foo).这种语法非常独特,即与ERE不同 - 扩展的globs使用前缀表示法(操作符出现before其操作数),而不是像ERE那样的后缀.
我想知道它支持类型的间隔表达式特征{n,m},即如果在大括号一个数,如前述的正则表达式被重复n时间或是否存在由逗号分隔的两个数字,前述正则表达式被重复n到m次.我找不到一个特定的文档,表明在扩展的glob中启用了这种支持.
我在今天的一个问题中遇到了一个要求,即只删除字符串中的一对尾随零.尝试使用扩展的glob支持来解决这个问题bash
给出一些样本字符串
foobar0000
foobar00
foobar000
Run Code Online (Sandbox Code Playgroud)
应该产生
foobar00
foobar
foobar0
Run Code Online (Sandbox Code Playgroud)
我尝试使用带参数扩展的扩展glob来做
x='foobar000'
Run Code Online (Sandbox Code Playgroud)
分别.我尝试使用下面的区间表达式,这对我来说显而易见,它不会起作用
echo ${x%%+([0]{2})}
Run Code Online (Sandbox Code Playgroud)
即类似于sed在ERE中使用sed -E 's/[0]{2}$//'或在BRE中使用sed 's/[0]\{2\}$//'
所以我的问题是,这是否可以使用任何扩展的glob运算符?我正在寻找特定于使用扩展的glob支持的答案,bash如果不可能也会采取'否'.
不知何故,我设法找到了一种在bash.
不!与 ksh 和 zsh 等其他 shell 相比,bash 没有实现用于通配符的区间表达式。
是的!然而,它并不实用,有时可以通过使用printf. {m,n}这个想法是使用 KSH-globs@(pattern)和来构建模拟间隔的球状表达式?(pattern)。
在下面的解释中,我们假设模式存储在变量中p
匹配n给定模式 ( {n}) 的出现次数:
这个想法是重复模式n次数。对于大n你可以使用printf
$ var="foobar01010"
$ echo ${var%%@(0|1)@(0|1)}
foobar000
Run Code Online (Sandbox Code Playgroud)
或者
$ var="foobar01010"
$ p=$(printf "@(0|1)%.0s" {1..4})
$ echo ${var%%$p}
foobar0
Run Code Online (Sandbox Code Playgroud)至少匹配m给定模式 ( {m,}) 的出现次数:
与之前相同,但多了一个*(pattern)
$ var="foobar01010"
$ echo ${var%%@(0|1)@(0|1)*(0|1)}
foobar
Run Code Online (Sandbox Code Playgroud)
或者
$ var="foobar01010"
$ p="(0|1)"
$ q=$(printf "@$p%.0s" {1..4})
$ echo ${var%%$q*$p}
foobar
Run Code Online (Sandbox Code Playgroud)匹配给n定m模式 ( {m,n}) 的出现次数:
区间表达式{n,m}意味着我们确实有n种出现和mn种可能的出现。这些可以使用 ksh-glob @(pat) n次和?(pat) mn次来构建。对于n=2和m=3,这导致:
$ var="foobar01010"
$ echo ${var%%@(0|1)@(0|1)?(0|1)}
foobar010
Run Code Online (Sandbox Code Playgroud)
或者
$ p="(0|1)"
$ q=$(printf "@$p%.0s" {1..n})$(printf "?$p%.0s" {n+1..m})
$ echo ${var%%$q}
foobar010
$ var="foobar00200"
foobar002
$ var="foobar00020"
foobar00020
Run Code Online (Sandbox Code Playgroud)
构造区间表达式的另一种方法{n,m}是使用 ksh-glob除了模式之外的任何内容,这样!(pat)我们就可以说:给我所有,除了......
man bash:!(pattern-list): 匹配除给定模式之一之外的任何内容
这样我们就可以写
$ echo ${var%%!(!(*$p)|@$p@$p@$p+$p|?$p)}
Run Code Online (Sandbox Code Playgroud)
或者
$ p="(0|1)"
$ pn=$(printf "@$p%.0s" {1..n})
$ pm=$(printf "?$p%.0s" {1..m-1})
$ echo ${var%%!(!(*$p)|$pn+$p|$pm)}
Run Code Online (Sandbox Code Playgroud)
注意:由于模式列表中存在或( ) ,因此需要在此处进行双重排除。|
区间表达式{n,m}已在中实现ksh93:
man ksh:
{n}(pattern-list)匹配n给定模式的出现。{m,n}(pattern-list)匹配m给n定模式的出现次数。如果m省略,0将被使用。如果n省略,至少m会匹配出现的次数。
$ echo ${var%%{2,3}(0|1)}
Run Code Online (Sandbox Code Playgroud)
也zsh有区间表达式的形式。它是一个全局标志,是选项的一部分EXTENDED_GLOB:
man zshall:
(#cN,M)该标志(#cN,M)可以在任何可以使用#or##运算符的地方使用,但在表达式(*/)#和(*/)##文件名生成中除外,其中/具有特殊含义;它不能与其他通配标志组合,如果放错位置,则会出现错误模式错误。相当于{N,M}正则表达式中的形式。前一个字符或组需要在N和时间之间匹配M(包括 和 时间)。表格(#cN)要求完全N匹配;(#c,M)相当于指定N为0;(#cN,)指定匹配数量没有最大限制。
$ echo ${var%%(0|1)(#c2,3)}
Run Code Online (Sandbox Code Playgroud)