
我有一個名為的變量,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"
答案1
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
基本正則表達式匹配單個字符,後面跟著該同一字符(它匹配 on aa
,而不是 on ab
)。這是以相同模式\1
對該捕獲組的反向引用。\(.\)
ksh93
確實支援其模式中的反向引用(例如ls -d -- @(?)\1
將列出由兩個相同字元組成的檔案名稱),而不是其他 shell。標準 BRE 和 PCRE 支援反向引用,但不支援標準 ERE,儘管某些 ERE 實作支援將其作為擴展。bash
's[[ foo =~ re ]]
使用 ERE。
[[ aa =~ (.)\1 ]]
不會匹配,但是
re='(.)\1'; [[ aa =~ $re ]]
如果系統的 ERE 支援的話可以。
答案2
您想要刪除第一個␣->␣
(不包括“箭頭”)和最後一個␣/
(包括空格和斜線)之後的所有內容。
string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}
$string
現在將是-> r1-ae0-2
。
相同的兩個替換將-> s7-Gi0-0-1:1-US / Foo
變成-> s7-Gi0-0-1:1-US
.
答案3
如果不知道確切的格式,就不可能明確回答這個問題每一個訊息需要。但是,作為一般方法,您可以使用以下方法列印某些特定欄位cut
:
$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US
或者你可以使用列印每第 n 列awk
:
$ awk -F' ' '{ for (i=2;i<=NF;i+=4) print $i }' <<< '-> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foo'
r1-ae0-2
s7-Gi0-0-1:1-US