Jest kilka ważnych rzeczy, które należy wiedzieć o [[ ]]
konstrukcji basha . Pierwszy:
Dzielenie na słowa i rozwijanie nazw plików nie są wykonywane na słowach pomiędzy [[
i ]]
; wykonywane są interpretacja tyldy, interpretacja parametrów i zmiennych, interpretacja wyrażeń arytmetycznych, podstawianie poleceń, podstawianie procesów i usuwanie cytatów.
Druga sprawa:
Dostępny jest dodatkowy operator binarny „= ~”, ... ciąg po prawej stronie operatora jest traktowany jako rozszerzone wyrażenie regularne i odpowiednio dopasowywany ... Dowolna część wzorca może być cytowana w cudzysłowie, aby wymusić dopasowanie jako ciąg .
W związku z tym $v
po obu stronach =~
zostanie rozwinięty do wartości tej zmiennej, ale wynik nie zostanie podzielony na słowa ani rozszerzony według nazwy ścieżki. Innymi słowy, pozostawienie rozszerzeń zmiennych bez cudzysłowów po lewej stronie jest całkowicie bezpieczne, ale trzeba wiedzieć, że rozszerzenia zmiennych będą występować po prawej stronie.
Więc jeśli piszesz: [[ $x =~ [$0-9a-zA-Z] ]]
The $0
wewnątrz regex po prawej stronie zostanie poszerzona przed regex jest interpretowany, co prawdopodobnie spowoduje regex niepowodzenie kompilacji (chyba ekspansji $0
kończy się cyfrą lub interpunkcyjny symbolu, którego wartość ASCII jest mniejsza niż cyfra). Jeśli w ten sposób zacytujesz prawą stronę [[ $x =~ "[$0-9a-zA-Z]" ]]
, to prawa strona będzie traktowana jako zwykły ciąg, a nie wyrażenie regularne (i $0
nadal będzie rozszerzana). To, czego naprawdę chcesz w tym przypadku, to[[ $x =~ [\$0-9a-zA-Z] ]]
Podobnie wyrażenie między [[
i ]]
jest dzielone na słowa przed interpretacją wyrażenia regularnego. Dlatego spacje w wyrażeniu regularnym muszą zostać zmienione lub cytowane. Jeśli chcesz, aby dopasować litery, cyfry lub spacje można użyć: [[ $x =~ [0-9a-zA-Z\ ] ]]
. Inne znaki podobnie muszą być poprzedzone znakami ucieczki, na przykład #
, które rozpoczynają komentarz, jeśli nie są cytowane. Oczywiście możesz umieścić wzorzec w zmiennej:
pat="[0-9a-zA-Z ]"
if [[ $x =~ $pat ]]; then ...
Wiele osób preferuje ten styl w przypadku wyrażeń regularnych zawierających wiele znaków, które musiałyby zostać usunięte lub zacytowane, aby przejść przez lekser basha. Ale uwaga: w tym przypadku nie możesz cytować rozwinięcia zmiennej:
if [[ $x =~ "$pat" ]]; then ...
Na koniec myślę, że to, co próbujesz zrobić, to sprawdzić, czy zmienna zawiera tylko prawidłowe znaki. Najłatwiejszym sposobem sprawdzenia tego jest upewnienie się, że nie zawiera nieprawidłowego znaku. Innymi słowy, wyrażenie takie jak to:
valid='0-9a-zA-Z $%&#'
if [[ ! $x =~ [^$valid] ]]; then ...
!
neguje test, zamieniając go na operator „nie pasuje”, a [^...]
klasa znaku regex oznacza „dowolny znak inny niż ...
”.
Połączenie interpretacji parametrów i operatorów regex może sprawić, że składnia wyrażeń regularnych bash będzie „prawie czytelna”, ale nadal istnieje kilka problemów. (Nie są tam zawsze?) Jednym z nich jest, że nie można umieścić ]
w $valid
, nawet jeśli $valid
były notowane, z wyjątkiem samego początku. (To jest reguła wyrażenia regularnego Posix: jeśli chcesz dołączyć ]
do klasy postaci, musi zaczynać się od początku. -
Może być na początku lub na końcu, więc jeśli potrzebujesz obu ]
i -
, musisz zacząć ]
i zakończyć -
, prowadząc do regex „wiem, co robię” emotikon: [][-]
)