
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
でサポートされる予定であることも記載されています。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 -- @(?)\1
2 つの同一文字で構成されるファイル名をリストします)、他のシェルはサポートしていません。標準 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