Answers:
ksh93
和zsh
具有反向引用(或更准确地1,在更换到捕获基团的参考文献)支撑件内${var/pattern/replacement}
,而不是bash
。
ksh93
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ printf '%s\n' "${var/*@(->*([[:space:]])+([^[:space:]]))*/\1}"
-> r1-ae0-2
zsh
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ set -o extendedglob
$ printf '%s\n' "${var/(#b)*(->[[:space:]]#[^[:space:]]##)*/$match[1]}"
-> r1-ae0-2
(mksh
手册页还提到,${KSH_MATCH[1]}
第一个捕获组将支持将来的版本。截至2017-04-25尚不可用)。
但是,使用bash
,您可以执行以下操作:
$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2
这样做会更好,因为它会检查首先找到该模式。
如果系统的regexps支持\s
/ \S
,则还可以执行以下操作:
re='->\s*\S+'
[[ $var =~ $re ]]
使用zsh
,您可以通过以下方式获得PCRE的全部功能:
$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2
使用zsh -o extendedglob
,另请参见:
$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2
便携性:
$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2
如果字符串中多次出现模式,则行为将随所有这些解决方案而变化。但是,它们都不会像grep
基于GNU 的解决方案那样为您提供所有匹配项的换行符分隔列表。
为此,您需要手动执行循环。例如,使用bash
:
re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
printf '%s\n' "${BASH_REMATCH[1]}"
var=${BASH_REMATCH[2]}
done
使用zsh
,您可以使用这种技巧将所有匹配项存储在数组中:
set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches
1反向引用确实更常见地指定了一种模式,该模式引用了较早的组所匹配的内容。例如,\(.\)\1
基本正则表达式匹配单个字符,后跟相同的字符(匹配于aa
,而不匹配ab
)。这\1
是\(.\)
在相同模式下对该捕获组的反向引用。
ksh93
确实在其模式中支持向后引用(例如,ls -d -- @(?)\1
将列出由两个相同字符组成的文件名),而不是其他shell。标准BRE和PCRE支持反向引用,但不支持标准ERE,尽管某些ERE实现支持将其作为扩展。bash
的[[ foo =~ re ]]
使用ERE。
[[ aa =~ (.)\1 ]]
不匹配,但是
re='(.)\1'; [[ aa =~ $re ]]
如果系统的ERE支持的话。