Bash parametre genişletmedeki referansları destekliyor mu?


15

Ben adında bir değişken var descrbir dize içerebilir Blah: -> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foovb Almak istediğim -> r1-ae0-2, -> s7-Gi0-0-1:1-USdizesinden parçasını. Şu anda bunun için kullanıyorum descr=$(grep -oP '\->\s*\S+' <<< "$descr". Bunu yapmanın daha iyi bir yolu var mı? Bunu parametre genişletme ile yapmak da mümkün müdür?

Yanıtlar:


20

ksh93ve içeride zshgeri referans (veya daha doğrusu 1 , yedek gruptaki yakalama gruplarına referanslar) desteği var ${var/pattern/replacement}, değil 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 sayfasında ayrıca gelecekteki sürümlerin ${KSH_MATCH[1]}ilk yakalama grubu için destekleneceği belirtiliyor. 2017-04-25 itibariyle henüz mevcut değil).

Ancak, bashşunları yapabilirsiniz:

$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
  printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2

Bu daha önce desenin bulunup bulunmadığını kontrol ettiği için daha iyidir.

Sisteminizin normal ifadeleri \s/ varsa \S, şunları da yapabilirsiniz:

re='->\s*\S+'
[[ $var =~ $re ]]

İle zsh, PCRE'lerin tüm gücünü aşağıdakilerle elde edebilirsiniz:

$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2

İle zsh -o extendedglob, ayrıca bkz:

$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2

portably:

$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2

Dizede desenin birkaç kez tekrarlanması durumunda, davranış tüm bu çözümlere göre değişir. Ancak bunların hiçbiri size GNU greptabanlı çözümünüzdeki gibi tüm karşılaşmaların satır satırından ayrı bir listesini vermeyecektir .

Bunu yapmak için, döngüyü elle yapmanız gerekir. Örneğin bash:

re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
  printf '%s\n' "${BASH_REMATCH[1]}"
  var=${BASH_REMATCH[2]}
done

İle zsh, bir dizideki tüm maçları saklamak için bu tür bir numaraya başvurabilirsiniz:

set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches

1 geri referanslar, daha önceki bir grup tarafından eşleşenlere referans veren bir paterni daha yaygın olarak tanımlar. Örneğin, \(.\)\1temel normal ifade tek bir karakterle ve ardından aynı karakterle (açık aadeğil, eşleşir ab) eşleşir . Bu \1, \(.\)aynı kalıptaki yakalama grubuna bir geri başvurudır .

ksh93kalıplarında geri başvuruları desteklemez (örneğin ls -d -- @(?)\1, iki kabuktan oluşan dosya adlarını listeler), diğer kabukları değil. Standart BRE'ler ve PCRE'ler geri referansları destekler, ancak standart ERE'yi desteklemez, ancak bazı ERE uygulamaları bunu bir uzantı olarak destekler. bash's [[ foo =~ re ]]kullanımları EREŞ.

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

eşleşmeyecek, ama

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

sistemin ERE'leri destekliyorsa olabilir.


9

İlkine kadar ␣->␣("ok" dahil değil) ve sondan sonra ␣/(boşluk ve eğik çizgi dahil ) her şeyi silmek istersiniz .

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

$stringşimdi olacak -> r1-ae0-2.

Aynı iki oyuncu değişikliği açacak -> s7-Gi0-0-1:1-US / Fooiçine -> s7-Gi0-0-1:1-US.


3

Her mesajın aldığı kesin formatı bilmeden bunu kesin olarak cevaplamak imkansızdır . Ancak, genel bir yaklaşım olarak aşağıdakileri kullanarak belirli alanları yazdırabilirsiniz cut:

$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US

Veya her n. Sütunu aşağıdakileri kullanarak yazdırabilirsinizawk :

$ 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.