Mam problemy ze zrozumieniem dopasowania wzorca ciągu z = ~ in bash .
Napisałem następującą funkcję ( nie przejmuj się – to tylko eksperymentowanie, a nie podejście do bezpieczeństwa z sumą md5):
md5 () { [[ "$(md5sum $1)" =~ $2* ]] && echo fine || echo baarr; }
i przetestowałem to z pewnym wejściem. Oto odniesienie:
md5sum wp.laenderliste b1eb0d822e8d841249e3d68eeb3068d3 wp.laenderliste
Niepotrzebnie trudno jest porównać, jeśli źródło sumy kontrolnej nie zawiera dwóch spacji z już nazwą pliku. To „Skąd pochodzą obserwacje, ale bardziej interesujące niż wiele sposobów rozwiązania tego problemu była moja obserwacja:
Definiuję zmienną kontrolną i testuję moją funkcję za pomocą zbyt krótkich, ale pasujących ciągów:
ok=b1eb0d822e8d841249e3d68eeb3068d3 for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i} ;done fine fine fine fine
Tego „oczekiwano i dobrze, ponieważ celem funkcji jest ignorowanie niedopasowania brakującej” wp.laenderliste „, a tym samym nawet dłuższych niezgodności .
Teraz, jeśli dołączę losowe rzeczy, które nie pasują, oczywiście spodziewam się błędów i otrzymam je:
for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}GU ;done baarr baarr baarr baarr
Zgodnie z oczekiwaniami. Ale jeśli jest tylko jeden, ostatni niezgodny znak , zobacz, co się stanie:
for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}G ;done fine fine fine fine
Czy to ja, nie zdając sobie sprawy, jak to powinno działać (funkcja zaznaczania jest zepsuta), czy czy naprawdę istnieje błąd „off-by-one-error” w dopasowywaniu wzorców basha?
Niedopasowania w środku ciągu mają znaczenie zliczenia 1:
for i in 5 9 e ; do echo md5 wp.laenderliste ${ok//$i/_} ;done md5 wp.laenderliste b1eb0d822e8d841249e3d68eeb3068d3 md5 wp.laenderliste b1eb0d822e8d84124_e3d68eeb3068d3 md5 wp.laenderliste b1_b0d822_8d841249_3d68__b3068d3 for i in 5 9 e ; do md5 wp.laenderliste ${ok//$i/_} ;done fine baarr baarr
Wersja bash:
bash -version GNU bash, Version 4.3.48(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2013 Free Software Foundation, Inc. Lizenz GPLv3+: GNU GPL Version 3 oder jünger <http://gnu.org/licenses/gpl.html>
Zrzeczenie się : md5sum jest użyteczne tylko w przypadku niezamierzonych błędów, a nie ataków. Nie zachęcam do korzystania z niego.
A to pytanie nie dotyczy poszukiwania lepszych rozwiązań ani obejścia. Chodzi o = ~ Operator, czy powinien działać tak, jak działa, a jeśli tak, dlaczego.
Odpowiedź
=~
in ([[ ]]
) to dopasowanie do wzorca wyrażenia regularnego (a raczej wyszukiwanie , patrz poniżej ). To „różni się od =
(lub ==
), które używają tych samych wzorców, co w przypadku symboli wieloznacznych.
W w szczególności gwiazdka w wyrażeniach regularnych oznacza „zero lub jedną kopię poprzedniej jednostki”, więc abc*
oznacza ab
plus zero lub więcej c
s.
W twoim przypadku końcowa gwiazdka sprawia, że ostatni znak argumentu funkcji jest opcjonalny. W ostatnim przykładzie wzorzec staje się ...68d3G*
, a ponieważ G*
pasuje do pustego ciągu, pasuje do ciągu takiego jak ...68d3
. Regexese for„ any string „ma wartość .*
lub„ dowolny znak, dowolna liczba razy ”.
Zwróć uwagę, że dopasowanie wyrażenia regularnego wyszukuje dopasowanie w dowolnym miejscu w ciągu, ale nie „Nie musi to być cały ciąg. Zatem wzorzec cde
zostałby znaleziony w ciągu abcdefgh
.
Możesz użyć czegoś takiego:
[[ "$(md5sum "$1")" = "$2 "* ]] && echo ok
Tak naprawdę nie potrzebujemy tutaj dopasowania wyrażenia regularnego, a ponieważ md5sum
zwraca końcową spację ( plus nazwa pliku) w każdym razie, możemy użyć tego we wzorcu, aby sprawdzić, czy dopasowujemy się do pełnego wzorca. Zatem podanie funkcji obciętego skrótu nie będzie pasować.
Komentarze
- Och, teraz czuję się brudny. Pracuję głównie z sedem, używając dopasowywania wzorców. Oczywiście muszę użyć. * i wiem o tym. Jakoś nauczyłem się teraz ewidentnie błędnego pomysłu, zapomnieć o kropce w powłoce – że ' to tylko przypadek dopasowania nazwy pliku, prawda? W przypadku / esac, kropka też jest potrzebna? I ' teraz wyglądam tak głupio!;)
- @userunknown,
case
używa tych samych wzorców co w przypadku nazwy pliku pasuje, więc*
pasuje do wszystkiego, a kropka to tylko kropka. Myślę, że=~
to chyba jedyne miejsce w powłoce, które używa wyrażeń regularnych. (Wtedy oczywiście ksh / Zsh / Bash mają rozszerzone bloki, które mają prawie taką samą funkcjonalność jak wyrażenia regularne, ale mają inną składnię. Musi być jednak jawnie włączone w Bash.) - Można również zrobić
[ "$(md5sum < "$1")" = "$2 -" ]
, aby usunąć zależność od ksh / zsh / bash (i uniknąć problemów z plikami, których nazwa zaczyna się od-
). - Ok, to dobra wymówka. Więc zgrubna pamięć, to dopasowanie wzorców w powłoce jest skomplikowane, było przynajmniej słuszne. Teraz czuję się dużo lepiej. 🙂 Teraz próbowałem
= $2.*
i to też działa, ale " $ 2 " * bądź lepszy.Ale to był tylko eksperyment, więc wygrałem ', nie używając niczego poza doświadczeniem edukacyjnym.
Odpowiedź
Nie użyłbym tutaj wyrażenia regularnego, tylko porównanie ciągów:
md5 () { sum=$(md5sum "$1" | awk "{print $1}") [[ $sum = "$2" ]] && echo fine || echo baarr; }