Tenho problemas para entender a correspondência de padrão de string com = ~ em bash .
Escrevi a seguinte função ( não se assuste – é apenas uma experiência, não uma abordagem de segurança com md5sum):
md5 () { [[ "$(md5sum $1)" =~ $2* ]] && echo fine || echo baarr; }
e testei com alguma entrada. Aqui estão algumas referências:
md5sum wp.laenderliste b1eb0d822e8d841249e3d68eeb3068d3 wp.laenderliste
É desnecessariamente difícil comparar, se a fonte para a soma de controle não contém os dois espaços em branco com o nome do arquivo. “É de onde vêm as observações, mas mais interessante do que as muitas maneiras de resolver esse problema foi minha observação:
Eu defino uma variável de controle e testo minha função com strings muito curtas, mas correspondentes:
ok=b1eb0d822e8d841249e3d68eeb3068d3 for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i} ;done fine fine fine fine
Isso “é esperado e bom, uma vez que é o propósito da função, ignorar a incompatibilidade do” wp.laenderliste “ausente e, portanto, incompatibilidades ainda mais longas .
Agora, se eu acrescentar coisas aleatórias, que não correspondem, espero, é claro, erros e os obtenho:
for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}GU ;done baarr baarr baarr baarr
Como esperado. Mas quando houver apenas um, último caractere incompatível , veja o que acontece:
for i in {29..32}; do md5 wp.laenderliste ${ok:1:$i}G ;done fine fine fine fine
Sou eu, sem perceber como isso deveria funcionar (o select está quebrado), ou existe realmente um erro aleatório na correspondência de padrões do bash?
Incompatibilidades no meio da questão da string desde a contagem 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
A versão 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>
Isenção de responsabilidade : md5sum é útil apenas contra erros não intencionais, não contra ataques. Não incentivo o seu uso.
E esta pergunta não é uma busca por melhores soluções ou soluções alternativas. É sobre = ~ Operador, se deve agir como age e, em caso afirmativo, por quê.
Resposta
=~
in ([[ ]]
) é uma correspondência de padrão de expressão regular (ou melhor, uma pesquisa , veja abaixo ) Isso é diferente de =
(ou ==
) que usa os mesmos padrões dos caracteres curinga de nome de arquivo.
Em Em particular, o asterisco em expressões regulares significa “zero ou uma cópia da unidade anterior”, então abc*
significa ab
mais zero ou mais c
s.
No seu caso, o asterisco final torna o caractere final do argumento da função opcional. Em seu exemplo final, o padrão se torna ...68d3G*
, e como G*
corresponde à string vazia, corresponde a uma string como ...68d3
. Regexese para” qualquer string “é de .*
, ou” qualquer caractere, qualquer número de vezes “.
Observe que a correspondência regexp procura uma correspondência em qualquer lugar da string, ela não “t precisa ser a string inteira . Portanto, o padrão cde
seria encontrado na string abcdefgh
.
Você pode querer usar algo assim:
[[ "$(md5sum "$1")" = "$2 "* ]] && echo ok
Não precisamos realmente de uma correspondência de expressão regular aqui, e já que md5sum
gera o espaço à direita ( mais o nome do arquivo) de qualquer forma, podemos usar isso no padrão para verificar se correspondemos ao padrão completo. Portanto, fornecer à função um hash truncado não corresponderia.
Comentários
- Oh, agora me sinto sujo. Trabalho principalmente com sed, quando uso a correspondência de padrões. É claro que tenho que usar. * e sei disso. De alguma forma, aprendi a ideia agora obviamente errada, que tenho esquecer o ponto no shell – que ' é apenas o caso para correspondência de nome de arquivo, certo? No caso de / esac, o ponto também é necessário? I ' estou parecendo tão estúpido, agora!;)
- @userunknown,
case
usa os mesmos padrões de nome de arquivo corresponde, portanto,*
corresponde a qualquer coisa e o ponto é apenas o ponto. Acho que=~
é o único lugar no shell que usa regexes. (Então, é claro, ksh / Zsh / Bash têm globs estendidos que têm praticamente a mesma funcionalidade que regexes, mas com sintaxe diferente. No entanto, ele precisa ser explicitamente ativado no Bash.) - Também se pode fazer
[ "$(md5sum < "$1")" = "$2 -" ]
para remover a dependência de ksh / zsh / bash (e evitar problemas com arquivos cujo nome começa com-
). - Ok, essa é uma boa desculpa. Portanto, a memória bruta, aquele casamento de padrões no shell é complicado, pelo menos estava certo. Agora me sinto muito melhor. 🙂 Agora tentei
= $2.*
e isso também funciona, mas " $ 2 " * funcionaria sê melhor.Mas foi apenas um experimento, então ' não usei nada, exceto a experiência de aprendizagem.
Resposta
Eu não usaria um regex aqui, apenas comparação de strings:
md5 () { sum=$(md5sum "$1" | awk "{print $1}") [[ $sum = "$2" ]] && echo fine || echo baarr; }