bash はパラメータ展開における後方参照をサポートしていますか?

bash はパラメータ展開における後方参照をサポートしていますか?

descr文字列 、 などを含むことができる というBlah: -> r1-ae0-2 / [123]名前の変数があります。文字列から、 の部分-> s7-Gi0-0-1:1-US / Fooを取得したいと考えています。現時点では、これに を使用しています。これを行うより良い方法はありますか? パラメータ展開を使用してこれを行うこともできますか?-> r1-ae0-2-> s7-Gi0-0-1:1-USdescr=$(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でサポートされる予定であることも記載されています。2017 年 4 月 25 日時点ではまだ利用できません)。${KSH_MATCH[1]}

ただし、 を使用すると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基本的な正規表現は、1 つの文字に続いて同じ文字に一致します (aaではなく に一致しますab)。これは、同じパターン内の\1そのキャプチャ グループへの後方参照です。\(.\)

ksh93はパターン内で後方参照をサポートしていますが (たとえば、 はls -d -- @(?)\12 つの同一文字で構成されるファイル名をリストします)、他のシェルはサポートしていません。標準 BRE と PCRE は後方参照をサポートしていますが、標準 ERE はサポートしていません。ただし、一部の ERE 実装は拡張機能としてこれをサポートしています。bash[[ 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

同じ 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

関連情報