Mám potíže s porozuměním řetězcového porovnávání vzorů s = ~ v bash .
Napsal jsem následující funkci ( nenechte se vyděsit – je to jen experimentování, ne bezpečnostní přístup s md5sum):
md5 () { [[ "$(md5sum $1)" =~ $2* ]] && echo fine || echo baarr; }
a vyzkoušeli jsme to s nějakým vstupem. Zde je nějaký odkaz:
md5sum wp.laenderliste b1eb0d822e8d841249e3d68eeb3068d3 wp.laenderliste
Je zbytečně těžké porovnávat, pokud zdroj pro kontrolní součet již neobsahuje dvě mezery s názvem souboru. „odkud pocházejí pozorování, ale zajímavější než mnoho způsobů, jak vyřešit tento problém, bylo moje pozorování:
Definuji řídicí proměnnou a otestuji svou funkci příliš krátkými, ale odpovídajícími řetězci:
ok=b1eb0d822e8d841249e3d68eeb3068d3 for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i} ;done fine fine fine fine
To je očekávané a v pořádku, protože je účelem této funkce, ignorovat nesoulad chybějícího „wp.laenderliste“, a proto ještě delší nesoulady .
Pokud nyní připojím náhodné věci, které se neshodují, očekávám samozřejmě chyby a dostanu je:
for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}GU ;done baarr baarr baarr baarr
Jak se očekávalo. Pokud však existuje pouze jeden, poslední nesouladný znak , podívejte se, co se stane:
for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}G ;done fine fine fine fine
Jsem to já, neuvědomuji si, jak to má fungovat (výběr je nefunkční), nebo existuje opravdu chyba při porovnávání vzorů v bash?
Neshody uprostřed řetězce od počtu 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
Verze 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>
Odmítnutí odpovědnosti : md5sum je užitečné pouze proti neúmyslným chybám, nikoli proti útokům. Nepodporuji jeho používání.
A tato otázka není hledáním lepších řešení ani alternativních řešení. Jde o = ~ Provozovatel, zda by měl jednat tak, jak funguje, a pokud ano, proč.
Odpovědět
=~
in ([[ ]]
) je shoda vzoru regulárního výrazu (nebo spíše vyhledávání , viz níže ). To se liší od =
(nebo ==
), který používá stejné vzory jako u zástupných znaků.
V hvězdička v regulárních výrazech konkrétně znamená „nula nebo jedna kopie předchozí jednotky“, takže abc*
znamená ab
plus nula nebo více c
s.
Koncová hvězdička ve vašem případě činí finální znak argumentu funkce volitelným. Ve vašem posledním příkladu se vzor stane ...68d3G*
a protože G*
odpovídá prázdnému řetězci, odpovídá řetězci jako ...68d3
. Regexese pro“ libovolný řetězec “ „is of .*
, nebo„ any character, any number of times „.
Všimněte si, že shoda regexp hledá shodu kdekoli v řetězci, ne „nemusí to být celý řetězec. Vzor cde
tedy najdete v řetězci abcdefgh
.
Možná budete chtít použít něco podobného:
[[ "$(md5sum "$1")" = "$2 "* ]] && echo ok
Zde opravdu nepotřebujeme shodu regulárního výrazu, a protože md5sum
vypíše koncový prostor ( plus název souboru), stejně to můžeme použít ve vzoru ke kontrole, že se shodujeme s úplným vzorem. Takže dát funkci zkrácený hash by se neshodoval.
Komentáře
- Ach, teď se cítím špinavý. Většinou pracuji s sed, když používám porovnávání vzorů. Tam samozřejmě musím použít. * a vím to. Nějak jsem se naučil nyní zjevně špatný nápad, zapomenout na tečku v shellu – že ' je pouze případ shody názvu souboru, že? V případě / esac je tečka také potřeba? I ' teď vypadám tak hloupě!;)
- @userunknown,
case
používá stejné vzory jako u názvu souboru odpovídá, takže*
odpovídá čemukoli a tečka je pouze tečka. Myslím, že=~
je asi jediné místo v shellu, které používá regulární výrazy. (Pak samozřejmě ksh / Zsh / Bash rozšířily globusy, které mají skoro stejnou funkcionalitu jako regulární výrazy, ale s odlišnou syntaxí. Musí to však být výslovně povoleno v Bash.) - Dalo by se také udělat
[ "$(md5sum < "$1")" = "$2 -" ]
odebrat závislost na ksh / zsh / bash (a vyhnout se problémům se soubory, jejichž název začíná-
). - Dobře, to je dobrá výmluva. Takže hrubá paměť, ta shoda vzorů v shellu je komplikovaná, měla alespoň pravdu. Nyní se cítím mnohem lépe. 🙂 Teď jsem zkusil
= $2.*
a také to funguje, ale " $ 2 " * by být lepší.Byl to však jen experiment, takže jsem ' nepoužil nic kromě zkušeností s učením.
Odpovědět
Zde bych nepoužíval regulární výraz, pouze porovnání řetězců:
md5 () { sum=$(md5sum "$1" | awk "{print $1}") [[ $sum = "$2" ]] && echo fine || echo baarr; }