bashはパラメータ拡張時の逆参照をサポートしますか?

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"これを使用しています。もっと良い方法がありますか?パラメータ拡張でこれを行うことはできますか?

答え1

ksh93代わりに、zsh逆参照(より正確には代替項目のキャプチャグループへの参照)の内部サポートがあります。${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 ]]

これにより、zshPCREのすべての機能を次のように取得できます。

$ 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

文字列でパターンが複数回発生する場合、これらの解決策はすべて異なる動作をします。しかし、それらのどれも、grepGNUベースのソリューションのように改行で区切られたすべての一致リストを提供するわけではありません。

これを行うには手動で繰り返す必要があります。たとえば、次のようになります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ではなくonと一致しますab)。これは、\1同じパターンのキャプチャグループの逆参照です。\(.\)

ksh93このモードは逆参照をサポートしますが、たとえばls -d -- @(?)\12つの同じ文字で構成されるファイル名が一覧表示されますが、他のシェルではサポートされません。逆参照は標準BREとPCREでサポートされていますが、標準EREではサポートされていません。ただし、一部のERE実装ではこれを拡張としてサポートしています。 EREを使用bashしてください[[ foo =~ re ]]

[[ 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

関連情報