Nie ma żadnego dobrego powodu
[[ $a = a|b ]]
Powinien zgłosić błąd zamiast sprawdzać, czy $ a jest a|bciągiem, a [[ $a =~ a|b ]]nie zwraca błędu.
Jedynym powodem jest to, że |ogólnie (na zewnątrz i wewnątrz [[ ... ]]) jest znakiem specjalnym. W tej [[ $a =pozycji bashoczekuje typu tokena, który jest normalnym SŁOWEM, takim jak argumenty lub cele przekierowań w normalnym wierszu poleceń powłoki (ale tak, jakby extglobopcja była włączona od wersji bash 4.1).
( WORD tutaj odnoszę się do słowa w hipotetycznej gramatyce powłoki, takiej jak opisana w specyfikacji POSIX , to znaczy, że powłoka byłaby analizowana jako jeden token w prostej linii poleceń powłoki, a nie inna definicja słów takich jak angielski jedna z sekwencji liter lub ciąg znaków niespacyjnych. foo"bar baz", $(echo x y)są dwoma takimi WORD s).
W normalnym wierszu poleceń powłoki:
echo a|b
Jest echo aprzesyłany do b. a|bnie jest WORD , to trzy tokeny: a WORD , |token i token b WORD .
W przypadku zastosowania w [[ $a = a|b ]], bashoczekuje WORD , który nie może ( a), ale potem stwierdza nieoczekiwany |znak, który powoduje błąd.
Co ciekawe, bashnie narzeka na:
[[ $a = a||b ]]
Ponieważ jest to teraz atoken, po którym następuje ||token b, więc jest on przetwarzany w ten sam sposób jak:
[[ $a = a || b ]]
Który testuje że $ajest aalbo że bciąg jest niepusty.
Teraz w:
[[ $a =~ a|b ]]
bashnie może mieć tej samej reguły analizowania. Posiadanie tej samej reguły analizowania oznaczałoby, że powyższe spowodowałoby błąd i należałoby zacytować to, |aby upewnić się, że a|bjest to jedno SŁOWO . Ale od wersji Bash 3.2, jeśli to zrobisz:
[[ $a =~ 'a|b' ]]
To już nie pasuje do a|bwyrażenia regularnego, ale do a\|bwyrażenia regularnego. Oznacza to, że cytowanie powłoki ma efekt uboczny usuwania specjalnego znaczenia operatorów wyrażeń regularnych. Jest to cecha, więc zachowanie jest podobne do tego [[ $a = "?" ]], ale wzory wieloznaczne (używane w [[ $a = pattern ]]) są SŁOWAMI powłoki (na przykład używanymi w globach), a wyrażenia regularne nie.
Więc bashmusi traktować wszystkich rozszerzonych operatorów wyrażeń regularnych, które są normalnie inaczej znaki specjalne powłoki, takie jak |, (, )inaczej podczas analizowania argument =~operatora.
Pamiętaj jednak, że podczas gdy
[[ $a =~ (ab)*c ]]
teraz działa
[[ $a =~ [)}] ]]
nie. Potrzebujesz:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
Który w poprzednich wersjach bashniepoprawnie pasowałby do odwrotnego ukośnika. Ten został naprawiony, ale
[[ $a =~ [^]')'] ]]
Czy nie zgadza się na backslashem tak jak powinien na przykład. Bo bashnie zdaje sobie sprawy, że )jest w nawiasie, więc ucieka )się doprowadzić do [^]\)]regexp, który pasuje na dowolnym charakterze, ale ], \i ).
ksh93 ma znacznie gorsze błędy na tym froncie.
W zsh, jest to normalne shell słowo, które jest oczekiwane i cytowanie operatory regexp nie wpływa na znaczenie operatorów regexp.
[[ $a =~ 'a|b' ]]
a|bPasuje do wyrażenia regularnego.
Oznacza to, że =~można również dodać do polecenia [/ test:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(również działają w yash. =~Należy podać w tym miejscu, zshponieważ =somethingjest tam specjalny operator powłoki).
bash 3.1 zachowywał się jak zsh. Zmieniło się w 3.2, prawdopodobnie, aby wyrównać ksh93(choć bashbyła to powłoka, która jako pierwsza wymyśliła [[ =~ ]]), ale nadal możesz zrobić BASH_COMPAT=31lub shopt -s compat31powrócić do poprzedniego zachowania (z wyjątkiem tego, że chociaż [[ $a =~ a|b ]]zwróci błąd w bash3.1, to już nie jest w bash -O compat31nowszych wersjach bash).
Mam nadzieję, że to wyjaśnia, dlaczego powiedziałem, że reguły są mylące i dlaczego używam:
[[ $a =~ $var ]]
pomaga w tym z przenośnością do innych powłok.
|jest specjalne) jest domyślnie włączone po prawej stronie[[ $var = $pattern ]]. Interesujące byłoby wyodrębnienie wersji ishoptkonfiguracji opcji, w których takie zachowanie jest widoczne - jeśli tylko te, w którychextglobjest włączony, domyślnie lub jawnie, to dobrze.