bash - 将区间表达式与 bash 扩展通配符一起使用
问题描述
我知道一个事实,它bash
支持带有正则表达式的扩展 glob,例如支持@(foo|bar)
,*(foo)
和?(foo)
. 这种语法非常独特,即与 ERE 的语法不同——扩展 glob 使用前缀表示法(运算符出现在before
其操作数的位置),而不是像 ERE 那样的后缀。
我想知道它是否支持类型的区间表达式功能,{n,m}
即如果大括号中有一个数字,前面的正则表达式重复n
多次,或者如果有两个数字用逗号分隔,前面的正则表达式重复n
多次m
。我找不到表明在扩展 glob 中启用此支持的特定文档。
实际问题
我今天在一个问题中遇到了一个要求,即只删除字符串中的一对尾随零。试图通过扩展的 glob 支持来解决这个问题bash
给定一些示例字符串,例如
foobar0000
foobar00
foobar000
应该产生
foobar00
foobar
foobar0
我尝试使用带参数扩展的扩展 glob 来做
x='foobar000'
分别。我尝试使用如下的区间表达式,这对我来说似乎很明显它不起作用
echo ${x%%+([0]{2})}
即sed
在 ERE 中用作sed -E 's/[0]{2}$//'
或在 BRE 中用作类似sed 's/[0]\{2\}$//'
所以我的问题是,这可能使用任何扩展的全局运算符吗?bash
如果不可能,我正在寻找特定于使用扩展 glob 支持的答案。
解决方案
不知何故,我设法在bash
.
间隔全局表达式是否在 bash 中实现?
不!与 ksh 和 zsh 等其他 shell 相比,bash 没有实现用于通配的区间表达式。
我们可以模仿 bash 中的区间表达式吗?
是的!但是,它并不实用,有时可以通过使用printf
. {m,n}
这个想法是使用 KSH-globs@(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次出现和mn次可能出现。这些可以使用 ksh-globs 构建@(pat)
n次和?(pat)
mn次。对于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)}
注意:由于模式列表中的或( ),您需要在此处进行双重排除。
|
其他贝壳呢?
KSH93
区间表达式{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
也zsh
有区间表达形式。它是一个 globbing 标志,是EXTENDED_GLOB
选项的一部分:
man zshall
:
(#cN,M)
该标志(#cN,M)
可用于任何可以使用#
or##
运算符的地方,除了在表达式(*/)#
和(*/)##
文件名生成中/
具有特殊含义的地方;它不能与其他 globbing 标志结合使用,如果放错位置,则会发生错误的模式错误。相当于{N,M}
正则表达式中的形式。前一个字符或组需要在N
和之间匹配M
,包括在内。表格(#cN)
要求完全N
匹配;(#c,M)
相当于指定N
为0
;(#cN,)
指定对匹配数没有最大限制。
$ echo ${var%%(0|1)(#c2,3)}
推荐阅读
- api - 如何在邮递员中传递这两个参数 --proxy-header "Proxy-Authorization: Basic xxxxxxxxxxxxxxx" --proxy abc.xyz.com:1234
- php - 在 Woocommerce 3 中为特定用户角色隐藏“运送到其他地址”
- javascript - 如何使整个表格行可点击,以便它检查复选框并更改按钮的颜色?
- python-3.x - 隔离表格中的第一行并下载csv链接(python)
- vb.net - 带有 read_committed 隔离的 Oracle ODP.net 事务的 VB.Net 在第一次调用后返回原始值
- angular - Primeng 可排序表指定排序列
- javascript - 如何判断代码是否在 try catch 块下
- php - 使用正则表达式将变量查找到字符串中
- perl - Perl 的 printf 宽度修饰符在地图运算符中不起作用
- javascript - React/Redux:我的道具在哪里?