String pattern-matching with = ~

Ik heb problemen om de string-patroon matching met = ~ in bash .

Ik schreef de volgende functie ( schrik niet – het is gewoon aan het experimenteren, geen beveiligingsbenadering met md5sum):

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

en testte het met wat input. Hier een verwijzing:

md5sum wp.laenderliste b1eb0d822e8d841249e3d68eeb3068d3 wp.laenderliste 

Het is onnodig moeilijk om te vergelijken, als de bron voor de controlesom niet de twee lege velden bevat met de bestandsnaam al. Dat Waar de observaties vandaan komen, maar interessanter dan de vele manieren om dat probleem op te lossen, was mijn observatie:

Ik definieer een controlevariabele en test mijn functie met te korte, maar overeenkomende strings:

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

Dat is te verwachten en prima, aangezien het het doel van de functie is, om de mismatch van de ontbrekende wp.laenderliste en dus zelfs langere mismatches te negeren .

Nu, als ik willekeurige dingen toevoeg, die niet overeenkomen, verwacht ik natuurlijk fouten en krijg ze:

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

Zoals verwacht. Maar als er slechts één, laatste niet-overeenkomend teken is, kijk dan wat er gebeurt:

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

Ben ik dit en besef ik niet hoe dit zou moeten werken (select is verbroken), of is er echt een één-voor-één-fout in de patroonafstemming van bash?

Mismatches in het midden van de string zijn van tel 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 

De bash-versie:

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> 

Disclaimer : md5sum is alleen nuttig tegen onbedoelde fouten, niet tegen aanvallen. Ik moedig het gebruik ervan niet aan.

En deze vraag is geen zoektocht naar betere oplossingen of tijdelijke oplossingen. Het gaat over de = ~ Operator, of hij zou moeten handelen zoals hij doet en zo ja, waarom.

Antwoord

=~ in ([[ ]]) is een reguliere expressie patroonovereenkomst (of liever, een zoekopdracht , zie hieronder ). Dat is anders dan = (of ==) die dezelfde patronen gebruikt als met jokertekens voor bestandsnamen.

In in het bijzonder betekent de asterisk in reguliere expressies “nul of één kopieën van de voorgaande eenheid”, dus abc* betekent ab plus nul of meer c s.

In jouw geval maakt de achterlopende asterisk het laatste teken van het functieargument optioneel. In jouw laatste voorbeeld wordt het patroon ...68d3G*, en aangezien G* overeenkomt met de lege string, komt het overeen met een string zoals ...68d3. Regexese voor” elke string “is van .*, of” elk teken, een willekeurig aantal keren “.

Merk op dat de regexp-overeenkomst ergens in de tekenreeks naar een overeenkomst zoekt, “t hoeft niet de hele string te zijn. Dus het patroon cde zou gevonden kunnen worden in de string abcdefgh.

Misschien wil je zoiets als dit gebruiken:

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

We hebben hier niet echt een reguliere expressie nodig, en aangezien md5sum de volgspatie ( plus bestandsnaam), kunnen we dat in het patroon gebruiken om te controleren of we overeenkomen met het volledige patroon. Dus het geven van een afgekapte hash aan de functie komt niet overeen.

Opmerkingen

  • Oh, nu voel ik me vies. Ik werk meestal met sed, wanneer ik patroonaanpassing gebruik. Daar moet ik natuurlijk gebruik van maken. * en weet het. Op de een of andere manier heb ik het nu duidelijk verkeerde idee geleerd, dat ik om de punt in de shell te vergeten – dat ' is alleen het geval voor het matchen van bestandsnamen, toch? In case / esac is de punt ook nodig? I ' Ik zie er zo stom uit, nu!;)
  • @userunknown, case gebruikt dezelfde patronen als bij de bestandsnaam komt overeen, dus * komt overal overeen, en de punt is gewoon de punt. Ik denk dat =~ ongeveer de enige plek in de shell is die regexes gebruikt. (Dan hebben ksh / Zsh / Bash natuurlijk uitgebreide globs die vrijwel dezelfde functionaliteit hebben als regexes, maar met een andere syntaxis. Het moet echter expliciet ingeschakeld zijn in Bash.)
  • Men zou ook kunnen doen [ "$(md5sum < "$1")" = "$2 -" ] om de afhankelijkheid van ksh / zsh / bash te verwijderen (en problemen te vermijden met bestanden waarvan de naam begint met -).
  • Ok, dat is een prima excuus. Dus het ruwe geheugen, dat patroonaanpassing in de schaal is gecompliceerd, klopte tenminste. Nu voel ik me veel beter. 🙂 Nu heb ik = $2.* geprobeerd en dit werkt ook, maar " $ 2 " * zou beter zijn.Maar het was maar een experiment, dus ik heb ' niets anders gebruikt dan de leerervaring.

Antwoord

Ik zou hier geen regex gebruiken, alleen stringvergelijking:

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

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *