bash 是否支持參數擴展中的反向引用?
我有一個名為的變數
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"
用於此。有一個更好的方法嗎?是否也可以通過參數擴展來做到這一點?
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 年 4 月 25 日尚不可用)。但是,使用
bash
,您可以執行以下操作:$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] && printf '%s\n' "${BASH_REMATCH[0]}" -> r1-ae0-2
哪個更好,因為它首先檢查是否找到了模式。
如果您的系統的正則表達式支持
\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
如果字元串中多次出現該模式,則行為將隨所有這些解決方案而變化。但是,它們都不會像在基於 GNU 的解決方案中那樣為您提供所有匹配項的換行符分隔列表
grep
。為此,您需要手動進行循環。例如,使用
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
基本正則表達式匹配單個字元後跟同一個字元(它匹配 onaa
,而不是 onab
)。這是以相同模式\1
對該擷取組的反向引用。\(.\)
ksh93
確實支持其模式中的反向引用(例如,ls -d -- @(?)\1
將列出由兩個相同字元組成的文件名),而不是其他 shell。標準 BRE 和 PCRE 支持反向引用,但不支持標準 ERE,儘管一些 ERE 實現支持它作為擴展。bash
的[[ foo =~ re ]]
使用 ERE。[[ aa =~ (.)\1 ]]
不匹配,但是
re='(.)\1'; [[ aa =~ $re ]]
如果系統的 ERE 支持它,則可能。