Mar*_*tin 20 bash string regular-expression variable-substitution
我有一个名为变量descr可以包含字符串Blah: -> r1-ae0-2 / [123],-> s7-Gi0-0-1:1-US / Foo等等。我想要得到的-> r1-ae0-2,-> s7-Gi0-0-1:1-US部分从字符串。目前我用descr=$(grep -oP '\->\s*\S+' <<< "$descr"这个。有一个更好的方法吗?是否也可以通过参数扩展来做到这一点?
Sté*_*las 23
ksh93并且在内部zsh有反向引用(或者更准确地说是1,对替换中捕获组的引用)支持${var/pattern/replacement},而不是bash.
ksh93:
$ var='Blah: -> r1-ae0-2 / [123]'
$ printf '%s\n' "${var/*@(->*([[:space:]])+([^[:space:]]))*/\1}"
-> r1-ae0-2
Run Code Online (Sandbox Code Playgroud)
zsh:
$ var='Blah: -> r1-ae0-2 / [123]'
$ set -o extendedglob
$ printf '%s\n' "${var/(#b)*(->[[:space:]]#[^[:space:]]##)*/$match[1]}"
-> r1-ae0-2
Run Code Online (Sandbox Code Playgroud)
(mksh手册页还提到未来版本将支持${KSH_MATCH[1]}第一个捕获组。截至 2017-04-25 尚不可用)。
然而,随着 bash,您可以执行以下操作:
$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2
Run Code Online (Sandbox Code Playgroud)
哪个更好,因为它检查首先找到模式。
如果您系统的正则表达式支持\s/ \S,您还可以执行以下操作:
re='->\s*\S+'
[[ $var =~ $re ]]
Run Code Online (Sandbox Code Playgroud)
使用zsh,您可以通过以下方式获得 PCRE 的全部功能:
$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2
Run Code Online (Sandbox Code Playgroud)
使用zsh -o extendedglob,另见:
$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2
Run Code Online (Sandbox Code Playgroud)
便携:
$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2
Run Code Online (Sandbox Code Playgroud)
如果字符串中多次出现该模式,则所有这些解决方案的行为都会有所不同。但是,它们都不会像在您的 GNU 中那样为您提供所有匹配项的换行符分隔列表-grep基于的解决方案。
为此,您需要手动进行循环。例如,使用bash:
re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
printf '%s\n' "${BASH_REMATCH[1]}"
var=${BASH_REMATCH[2]}
done
Run Code Online (Sandbox Code Playgroud)
使用zsh,您可以使用这种技巧将所有匹配项存储在一个数组中:
set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches
Run Code Online (Sandbox Code Playgroud)
1 back-references 更常见地指定一种模式,该模式引用较早组匹配的内容。例如,\(.\)\1基本的正则表达式匹配单个字符后跟同一个字符(它匹配 on aa,而不匹配on ab)。这\1是对那个的反向引用\(.\)对相同模式中捕获组。
ksh93在其模式中支持反向引用(例如ls -d -- @(?)\1将列出由两个相同字符组成的文件名),而不是其他 shell。标准 BRE 和 PCRE 支持反向引用,但不支持标准 ERE,尽管一些 ERE 实现支持它作为扩展。bash's[[ foo =~ re ]]使用 ERE。
[[ aa =~ (.)\1 ]]
Run Code Online (Sandbox Code Playgroud)
不会匹配,但是
re='(.)\1'; [[ aa =~ $re ]]
Run Code Online (Sandbox Code Playgroud)
如果系统的 ERE 支持它,可能会。
您想删除第一个?->?(不包括“箭头”)和最后一个?/(包括空格和斜线)之后的所有内容。
string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}
Run Code Online (Sandbox Code Playgroud)
$string现在将是-> r1-ae0-2。
相同的两个替换将-> s7-Gi0-0-1:1-US / Foo变成-> s7-Gi0-0-1:1-US.