Test bash: co robi „= ~”?

40
#!/bin/bash
INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then

echo "INT is an integer."

else

echo "INT is not an integer." >&2

exit 1

fi

Co prowadzi wiodący ~w początkowym wyrażeniu regularnym?

ragnarok
źródło
3
To nie jest wyrażenie regularne, to wzór testowy do ustalenia dopasowania wyrażenia regularnego ...
jasonwryan
5
Czy przeczytałeś instrukcję bash? Co uważasz za niejasne?
icarus
3
Przeszukaj stronę podręcznika bash dla = ~
Jeff Schaller

Odpowiedzi:

46

W ~rzeczywistości jest częścią operatora, =~który wykonuje dopasowanie wyrażenia regularnego łańcucha po lewej stronie do rozszerzonego wyrażenia regularnego po prawej stronie.

[[ "string" =~ pattern ]]

Zauważ, że ciąg powinien być cytowany, a wyrażenie regularne nie powinno być cytowane.

Podobny operator jest używany w języku programowania Perl.

Wyrażenia regularne rozumiane przez bashsą takie same jak te, które GNU greprozumie z -Eflagą, tj. Rozszerzony zestaw wyrażeń regularnych.


Trochę nie na temat, ale warto wiedzieć:

W przypadku dopasowania do wyrażenia regularnego zawierającego grupy przechwytujące część ciągu przechwycona przez każdą grupę jest dostępna w BASH_REMATCHtablicy. Zerowego / pierwsza pozycja w tej tablicy odpowiada się &w strukturze zastępczej sed„s polecenia podstawienia (lub $&Perl), która jest trochę łańcucha, który pasuje do wzorca, natomiast wpisy w indeksie 1 i dalej odpowiada \1, \2itp . w sedstrukturze zastępczej (lub $1, $2itp Perl), czyli bity dopasowane każdego nawiasach.

Przykład:

string=$( date +%T )

if [[ "$string" =~ ^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$ ]]; then
  printf 'Got %s, %s and %s\n' \
    "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
fi

To może wygenerować

Got 09, 19 and 14

jeśli aktualny czas zdarzy się 09:19:14.

REMATCHBit BASH_REMATCHnazwa macierzy pochodzi od „Dopasowanie wyrażenia regularnego”, czyli „Re-Match”.


W bashpowłokach innych niż Bourne'a można również używać exprdo ograniczonego dopasowywania wyrażeń regularnych (używając tylko podstawowych wyrażeń regularnych).

Mały przykład:

$ string="hello 123 world"
$ expr "$string" : ".*[^0-9]\([0-9][0-9]*\)"
123
Kusalananda
źródło
2
Jest to to samo, co grep -Erozumie tylko w systemach GNU i tylko wtedy, gdy jako wzorzec używana jest niecytowana zmienna [[ $var = $pattern ]](patrz [[ 'a b' =~ a\sb ]]vs p='a\sb'; [[ 'a b' =~ $p ]]). Uważaj również, aby cytowanie powłoki wpłynęło na znaczenie operatorów RE i że niektóre znaki muszą być cytowane dla tokenizacji powłoki, która może wpływać na przetwarzanie RE. [[ '\' =~ [\/] ]]zwraca false ksh93ma jeszcze gorsze problemy. Zobacz zsh(lub bash 3.1), aby uzyskać bardziej rozsądne podejście, w którym cytowanie powłoki i RE jest wyraźnie oddzielone. [Wbudowane w zshi yashteż =~operator.
Stéphane Chazelas
2
bardzo fajnie off-topic! +1 (
JJoao
@ StéphaneChazelas Jak to jest „zdrowsze”, że oba te mecze w Zsh ?: [[ "This is a fine mess." =~ T.........fin*es* ]]; [[ "This is a fine mess." =~ T.........fin\*es\* ]]. A może cytowany *również pasuje? [[ "This is a fine mess." =~ "T.........fin*es*" ]].
sorontar
Jest to rozsądniejsze (IMO), ponieważ ma znacznie prostsze zasady. Cytowanie powłoki i ucieczka RE są wyraźnie oddzielne. W [[ a =~ .* ]]lub [[ a =~ '.*' ]]lub [[ a =~ \.\* ]]ta sama .*RE jest przekazywana do =~operatora. OTH, w bash, [[ '\' =~ [)] ]]zwraca błąd, nie wiesz, nie próbując go czy [[ '\' =~ [\)] ]]meczów? Co powiesz na [[ '\' =~ [\/] ]](robi to w ksh93). Co powiesz na c='a-z'; [[ a =~ ["$c"] ]](porównaj z =operatorem)? Zobacz także: [[ '\' =~ [^]"."] ]]która zwraca fałszywe ... Zauważ, że można zrobić shopt -s compat31w bashcelu uzyskania zshzachowanie.
Stéphane Chazelas
zsh/ bash -o compat31Jest zachowanie przez [[ a =~ '.*' ]]to również zgodne z [ a '=~' '.*' ](do [implementacji tego wsparcia =~) lub expr a : '.*'. OTOH, to nie jest spójne z [[ a = '*' ]]vs [[ a = * ]](ale wtedy globusy są częścią języka powłoki, podczas gdy RE nie są).
Stéphane Chazelas
4

Powinieneś przeczytać strony podręcznika bash, w [[ expression ]]sekcji.

An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)).

Krótko mówiąc, =~jest operatorem, podobnie jak ==i !=. Nie ma to nic wspólnego z rzeczywistym wyrażeniem regularnym w ciągu po prawej stronie.

Sokel
źródło
Czy możesz wymyślić kilka przykładów demonstrujących użycie =~w prawdziwym życiu ...?
George Vasiliou
1
@GeorgeVasiliou Używam go dość często w skryptach, które umieszczają dane wyjściowe polecenia w zmiennej. Następnie zmienna jest sprawdzana, aby sprawdzić, czy pasuje do jakiegoś wzorca ciągu. Jest to przydatne na przykład, jeśli chcesz podjąć pewne działania w oparciu o dane wyjściowe błędu tego polecenia.
Michael Martinez
@Sokel Dla niektórych „RTFM” łatwiej powiedzieć niż zrobić. ⋯ man [[ expresssion ]]i man [[nic nie zwracaj . help [[zwraca przydatne informacje - od [[wewnętrznej komendy bash - ale nie mówi, czy =~używa podstawowej czy rozszerzonej składni wyrażenia regularnego. ⋯ Cytowany tekst pochodzi ze strony podręcznika użytkownika bash . Zdaję sobie sprawę, że powiedziałeś „czytaj strony podręcznika bash”, ale na początku myślałem, że masz na myśli przeczytanie stron podręcznika bash. W każdym razie man bashzwraca ogromny plik, który ma 4139 linii (72 strony). Można go przeszukiwać naciskając /▒▒▒, co wymaga wyrażenia regularnego, którego smak - podobny =~- nie jest określony.
Alex Quinn