Wyodrębnianie łańcucha, zgodnie ze wzorem, w skrypcie bash

17

Załóżmy, że mam ciąg znaków strname:

strname="ph7go04325r"

Chciałbym wyodrębnić znaki między pierwszym "3" znakiem a ostatnim "r" znakiem w strname, zapisując wynik w ciągu strresult. W powyższym przykładzie wynikiem strresultbyłoby:

strresult="25"

Pierwszy "3"znak niekoniecznie musi znajdować się w pozycji łańcucha 8 w strname; Podobnie, ostatnia "r"jest nie zawsze w pozycji łańcucha 11. Tak więc, zarówno z następujących ciągów strnamepowinien dawać strresult="25":

strname="ph11go04325raa"
strname="325r"
strname="rgo04325raa"

Również strname=ph12go04330raa"powinien ustąpić strresult="30".

Jestem nowym użytkownikiem skryptów bashowych i nie wiem, od czego zacząć takie dopasowywanie wzorców łańcuchów. Masz jakieś sugestie?

Andrzej
źródło

Odpowiedzi:

28

Aby to zrobić, możesz użyć wyrażenia regularnego w bash (3.0 lub nowszy):

if [[ $strname =~ 3(.+)r ]]; then
    strresult=${BASH_REMATCH[1]}
else
    echo "unable to parse string $strname"
fi

W bash grupy przechwytywania z wyrażenia regularnego są umieszczane w specjalnej tablicy BASH_REMATCH. Element 0 zawiera całe dopasowanie, a 1 zawiera dopasowanie dla pierwszej grupy przechwytywania.

Jordan
źródło
10

W standardowej shskładni (działałoby to z dowolną wersją bashlub inną powłoką zgodną z POSIX), zrobiłbyś:

case $strname in
  (*3*r*) 
    strresult=${strname#*3}
    strresult=${strresult%r*};;
  (*)
    printf >&2 '%s\n' "Unable to parse string $strname"
esac

Zobacz także stare exprrozwiązanie, które działa nawet na 35-letnich Unikach:

expr "x$strname" : 'x[^3]*3\(.*\)r'

Stary cokół z exprjest to, że jeśli mecz nie masz status wyjścia niezerową (Fine), ale można również uzyskać status wyjścia niezerową jeśli Zwracany smyczki postanawia 0 (jak w przypadku strname=zz300rzz).

Stéphane Chazelas
źródło
Myślę, że twoje sformułowanie niepoprawnie sugeruje, że można to zrobić tylko ze starszymi wersjami bash. Rozszerzanie parametrów jest oczywiście nadal dobrym podejściem w nowoczesnych powłokach.
kojiro
1
@kojiro, rozumiem o co ci chodzi. Wstępne sformułowanie miało stanowić kontynuację odpowiedzi Jordana. Zaktualizowałem swoją odpowiedź.
Stéphane Chazelas,