Isto é o que estou usando agora para fazer o trabalho:
#!/bin/sh --
string='Aa1!z'
if ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:upper:]]' || \
! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:lower:]]' || \
! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:digit:]]' || \
! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:punct:]]'; then
printf '%s\n' 'String does not meet your requirements'
else
printf '%s\n' 'String meets your requirements'
fi
Isso é extremamente ineficiente e verboso. Existe uma maneira melhor de fazer isso?
awk
Com correspondência de padrões flexível :Com uma chamada para
awk
e sem pipe:Isso é POSIX, mas observe que
mawk
ainda não suporta classes de caracteres POSIX. O--
não é necessário com s compatíveis com POSIXawk
, mas seria em versões mais antigas do busyboxawk
(o que bloquearia os valores$string
que começam com-
).Uma variante dessa função usando uma
case
construção de shell:Observe, no entanto, que alterar a localidade para o shell no meio de um script não funciona com todas as
sh
implementações (portanto, você precisaria que o script já fosse chamado na localidade C se desejar que a entrada seja considerada como codificada em o conjunto de caracteres de localidade C e as classes de caracteres para corresponder apenas aos especificados por POSIX).O script a seguir é mais longo que seu código, mas mostra como você pode testar uma string em uma lista de padrões. O código detecta se a string corresponde a todos os padrões ou não e imprime um resultado.
O
case ... esac
comando composto é a maneira POSIX de testar uma string em relação a um conjunto de padrões globbing. A variável$pattern
é usada sem aspas no teste, para que a correspondência não seja feita como uma comparação de string. Se a string não corresponder ao padrão fornecido, ela corresponderá*
e o loop será encerrado após a configuraçãofailed
comotrue
.Executando isso renderia
Você poderia guardar o teste em uma função assim (o código testa várias strings em um loop, chamando a função):
Se você deseja definir
LC_ALL=C
localmente na função, escreva-a comoObserve que o corpo da função agora está em um sub-shell. A configuração
LC_ALL=C
, portanto, não afetará o valor dessa variável no ambiente de chamada.Obtenha a função shell para receber os padrões como argumentos também, e você basicamente obtém a resposta de Stéphane Chazelas (a variante) .
Inspirado em RomanPerekhrest, mas com alguns pequenos refinamentos para acabar com o pipeline e a substituição de comandos:
Esta é a resposta de RomanPerekhrest reescrita para trabalhar com mawk:
Ele também pega emprestado da resposta do bxm usando o código de saída do awk em vez de verificar se a saída do awk está vazia.
Roubando descaradamente de @HaroldFischer @bxm e @RomanPerekhrest por uma
awk
solução puraPara completar, uma vez que nenhuma outra resposta menciona o PCRE. Uma limitação do BRE/ERE é que você não pode implementar trivialmente¹ um lógico e para o equivalente lógico "ou" em alternância com
|
.Os padrões PCRE permitem que você crie condições "e" usando asserções de largura zero: antecipar ou antecipar. Esses "não consomem" caracteres, mas restringem a correspondência de padrões antes ou depois. Há muitas maneiras de usá-los, antecipar antecipadamente faz sentido aqui:
O PCRE aplica 4 "pré-condições" à entrada antes de aplicar a correspondência
.{4,}
(4 ou mais caracteres, sinta-se à vontade para aumentar ;-). Um ponto a ser observado é que "(?=[[:upper:]])
" só inspecionará um único caractere, portanto, cada condição é precedida por ".*
" para que toda a entrada seja verificada.pcregrep
também suporta uma localidade via--locale=C
.Uma vez que o "P" em PCRE significa
perl
:faz a mesma coisa para uma única linha de entrada (não é uma substituição geral para "
pcregrep -q
").Um superconjunto impressionante desse tipo de problema pode ser encontrado aqui: https://stackoverflow.com/questions/469913/regular-expressions-is-there-an-and-operator
¹ Você pode expandir um ERE para emular "e" por permutações:
Definitivamente não vai ajudar a ser "ineficaz e verboso".
Abaixo cria uma senha aleatória com o solicitado. Você pode tornar a senha mais longa substituindo
head -c 12
por um valor maior.