bashはパラメーター展開で後方参照をサポートしますか?


15

私が持っているという名前の変数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"これに使用しています。これを行うためのより良い方法はありますか?パラメータ拡張でこれを行うことも可能ですか?

回答:


20

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

mkshmanページでは、将来のバージョン${KSH_MATCH[1]}では最初のキャプチャグループでサポートされることも記載されています。2017-04-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\(.\)、同じパターンのキャプチャグループへの後方参照です。

ksh93ls -d -- @(?)\1他のシェルではなく、そのパターンで後方参照をサポートします(たとえば、2つの同一の文字で構成されるファイル名をリストします)。標準のBREとPCREは後方参照をサポートしていますが、標準EREはサポートしていませんが、一部のERE実装では拡張としてサポートしています。bash「S [[ foo =~ re ]]のusesのEREを。

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

一致しませんが、

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

システムのEREがサポートしている場合があります。


9

最初␣->␣(「矢印」を含まない)までと、最後␣/(スペースとスラッシュを含む)の後ろのすべてを削除したい。

string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}

$string今になります-> r1-ae0-2

同じ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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.