Strängmönstermatchning med = ~

Jag har problem med att förstå strängmönstermatchningen med = ~ i bash .

Jag skrev följande funktion ( var inte orolig – det är bara att experimentera, inte en säkerhetsmetod med md5sum):

md5 () { [[ "$(md5sum $1)" =~ $2* ]] && echo fine || echo baarr; } 

och testade det med en del inmatningar. Här referens:

md5sum wp.laenderliste b1eb0d822e8d841249e3d68eeb3068d3 wp.laenderliste 

Det är onödigt svårt att jämföra, om källan för styrsumman inte innehåller de två blankstegen med filnamnet redan. ”där observationerna härstammar från, men mer intressant än de många sätten att lösa problemet var min observation:

Jag definierar en kontrollvariabel och testar min funktion med för korta, men matchande strängar:

ok=b1eb0d822e8d841249e3d68eeb3068d3 for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i} ;done fine fine fine fine 

Det är förväntat och bra, eftersom det är syftet med funktionen, att ignorera bristande matchning av den saknade ”wp.laenderliste” och därmed ännu längre matchningar .

Om jag nu lägger till slumpmässiga saker, som inte matchar, förväntar jag mig naturligtvis fel och får dem:

for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}GU ;done baarr baarr baarr baarr 

Som förväntat. Men när det finns bara ett, sista felaktigt tecken , se vad som händer:

for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}G ;done fine fine fine fine 

Är det jag som inte inser hur detta ska fungera (select är trasigt), eller finns det verkligen ett off-by-one-fel i bashs mönstermatchning?

Fel i mitten av strängmaterialet från räkning 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 

Bash-versionen:

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> 

Ansvarsfriskrivning : md5sum är bara användbart mot oavsiktliga misstag, inte mot attacker. Jag uppmuntrar inte att använda det.

Och den här frågan är inte en sökning efter bättre lösningar eller lösningar. Det handlar om = ~ Operatör, om den ska agera som den gör och i så fall varför.

Svar

=~ in ([[ ]]) är en regelbunden uttrycksmatchning (eller snarare en sökning , se nedan ). Det skiljer sig från = (eller ==) som använder samma mönster som med jokertecken för filnamn.

I särskilt betyder asterisken i reguljära uttryck ”noll eller en kopia av föregående enhet”, så abc* betyder ab plus noll eller mer c s.

I ditt fall gör den efterföljande asterisken den sista karaktären i funktionsargumentet valfri. I ditt sista exempel blir mönstret ...68d3G*, och eftersom G* matchar den tomma strängen, matchar den en sträng som ...68d3. Regexese för” vilken sträng som helst ”är av .* eller” vilket tecken som helst, vilket antal gånger som helst ”.

Observera att regexp-matchningen söker efter en matchning var som helst i strängen, den gör det inte ”t måste vara strängen hela . Så mönstret cde hittades i strängen abcdefgh.

Du kanske vill använda något så här:

[[ "$(md5sum "$1")" = "$2 "* ]] && echo ok 

Vi behöver inte riktigt matcha ett reguljärt uttryck här, och eftersom md5sum matar ut det bakre utrymmet ( plus filnamn) hur som helst kan vi använda det i mönstret för att kontrollera att vi matchar hela mönstret. Så att ge funktionen en trunkerad hash skulle inte matcha.

Kommentarer

  • Åh, nu känner jag mig smutsig. Jag arbetar mest med sed, när jag använder mönstermatchning. Det måste jag naturligtvis använda. * och vet det. På något sätt har jag lärt mig den nu uppenbart fel idén, att jag har att glömma bort pricken i skalet – att ' bara är fallet för filnamnmatchning, eller hur? I fallet / esac behövs punkten också? I ' jag ser så dum ut nu!;)
  • @userunknown, case använder samma mönster som med filnamn matchar, så * matchar vad som helst, och punkten är bara punkten. Jag tror att =~ är ungefär det enda stället i skalet som använder regexes. (Då har naturligtvis ksh / Zsh / Bash utökade globs som har ungefär samma funktionalitet som regexes, men med olika syntax. Det måste dock uttryckligen aktiveras i Bash.)
  • Man kan också göra [ "$(md5sum < "$1")" = "$2 -" ] för att ta bort beroendet av ksh / zsh / bash (och undvika problem med filer vars namn börjar med -).
  • Ok, det är en bra ursäkt. Så det grova minnet, det mönstermatchningen i skalet är komplicerat, var åtminstone rätt. Nu mår jag mycket bättre. 🙂 Nu försökte jag = $2.* och det fungerar också, men " $ 2 " * skulle bli bättre.Men det var bara ett experiment, så jag vann ' att inte använda något annat än inlärningsupplevelsen.

Svar

Jag skulle inte använda en regex här, bara strängjämförelse:

md5 () { sum=$(md5sum "$1" | awk "{print $1}") [[ $sum = "$2" ]] && echo fine || echo baarr; } 

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *