我知道一个事实,bash
支持带有正则表达式的扩展glob,例如对@(foo|bar)
,*(foo)
和?(foo)
的支持。这种语法非常独特,即与ERE不同 - 扩展的globs使用前缀表示法(运算符出现before
的操作数),而不是像ERE那样的后缀。
我想知道它是否支持类型{n,m}
的区间表达式功能,即如果大括号中有一个数字,则前面的正则表达式重复n
次,或者如果有两个数字由...分隔逗号,前面的正则表达式重复n
到m
次。我找不到一个特定的文档,表明在扩展的glob中启用了这种支持。
我在今天的一个问题中遇到了一个要求,即只删除一个字符串中的一对尾随零。尝试使用bash
给出一些像
这样的示例字符串foobar0000
foobar00
foobar000
应该产生
foobar00
foobar
foobar0
我尝试使用带参数扩展的扩展glob来执行
x='foobar000'
分别。我尝试使用下面的区间表达式,这对我来说显而易见,它不起作用
echo ${x%%+([0]{2})}
即。在ERE中使用sed
作为sed -E 's/[0]{2}$//'
或在BRE中使用sed 's/[0]\{2\}$//'
所以我的问题是,这是否可以使用任何扩展的glob运算符?我正在寻找特定于bash
中使用扩展glob支持的答案,如果不可能则会采用'否'。
答案 0 :(得分:3)
不知怎的,我设法在bash
的限制范围内找到了解决方法。
没有!与其他shell(如ksh和zsh)相比,bash没有实现globbing的区间表达式。
是的!但是,它实际上并不实用,有时可以通过printf
获益。我们的想法是使用KSH-globs {m,n}
和@(pattern)
构建模仿?(pattern)
区间的球形表达式。
在下面的解释中,我们假设模式存储在变量p
匹配给定模式的n
次出现({n}
):
我们的想法是重复n
次模式。对于大型 n ,您可以使用printf
$ var="foobar01010"
$ echo ${var%%@(0|1)@(0|1)}
foobar000
或
$ var="foobar01010"
$ p=$(printf "@(0|1)%.0s" {1..4})
$ echo ${var%%$p}
foobar0
匹配给定模式的至少m
次出现({m,}
):
与以前相同,但附加*(pattern)
$ var="foobar01010"
$ echo ${var%%@(0|1)@(0|1)*(0|1)}
foobar
或
$ var="foobar01010"
$ p="(0|1)"
$ q=$(printf "@$p%.0s" {1..4})
$ echo ${var%%$q*$p}
foobar
从n
到m
次出现的给定模式({m,n}
)匹配:
区间表达式{n,m}
意味着我们肯定有 n 外观和 m-n 可能的外观。这些可以使用ksh-globs @(pat)
n 次和?(pat)
m-n 次构建。对于 n = 2 和 m = 3 ,这会导致:
$ var="foobar01010"
$ echo ${var%%@(0|1)@(0|1)?(0|1)}
foobar010
或
$ 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
构造区间表达式{n,m}
的另一种方法是使用ksh-glob 除了!(pat)
之外的任何模式,它允许我们说:给我所有,除了。 ..
<强>
man bash
强>!(pattern-list)
:匹配除了某个给定模式之外的任何内容
这样我们就可以写
了$ echo ${var%%!(!(*$p)|@$p@$p@$p+$p|?$p)}
或
$ p="(0|1)"
$ pn=$(printf "@$p%.0s" {1..n})
$ pm=$(printf "?$p%.0s" {1..m-1})
$ echo ${var%%!(!(*$p)|$pn+$p|$pm)}
注意:由于模式列表中的或(|
),您需要在此处进行双重排除。
区间表达式{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)}
zsh
也有一种区间表达形式。它是一个globbing标志,它是EXTENDED_GLOB
选项的一部分:
<强>
man zshall
强>
(#cN,M)
可以在(#cN,M)
或#
运算符可以使用的任何位置使用标记##
,但表达式(*/)#
和{{1}除外在文件名生成中,(*/)##
具有特殊含义;它不能与其他globbing标志组合使用,如果放错位置会发生错误的模式错误。它等同于正则表达式中的/
形式。上一个字符或组必须在{N,M}
和N
次之间进行匹配。表格M
完全需要(#cN)
次匹配;N
相当于将(#c,M)
指定为N
;0
指定匹配数量没有最大限制。
(#cN,)
答案 1 :(得分:1)
[[...]]
或=
运算符时,filename expansion和!=
conditional constructs使用模式匹配。文件名扩展用于参数扩展。[set]{count}
这样的表达式。例如,我们可以使用+(..)
匹配一个或多个匹配项,依此类推,但指定模式的出现次数是不可能的。^
和$
),但我们可以使用${parameter%%word}
参数扩展来删除参数的尾部。所以这将有效:
var='foobar000'
echo ${var%%[0][0]}
并且,通过一些简单的黑客行为,我们可以做到这一点:
var='foobar000'
echo ${var%%$(yes '[0]' | head -n 2 | tr -d '\n')}
这将从字符串中删除两个尾随零。