Bash

bash 是否支持參數擴展中的反向引用?

  • April 25, 2017

我有一個名為的變數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"用於此。有一個更好的方法嗎?是否也可以通過參數擴展來做到這一點?

ksh93zsh在內部支持反向引用(或更準確地說是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基本正則表達式匹配單個字元後跟同一個字元(它匹配 on aa,而不是 on ab)。這是以相同模式\1對該擷取組的反向引用。\(.\)

ksh93確實支持其模式中的反向引用(例如,ls -d -- @(?)\1將列出由兩個相同字元組成的文件名),而不是其他 shell。標準 BRE 和 PCRE 支持反向引用,但不支持標準 ERE,儘管一些 ERE 實現支持它作為擴展。bash[[ foo =~ re ]]使用 ERE。

[[ aa =~ (.)\1 ]]

不匹配,但是

re='(.)\1'; [[ aa =~ $re ]]

如果系統的 ERE 支持它,則可能。

引用自:https://unix.stackexchange.com/questions/361134