Por que testar $? -eq 0 é verdade mesmo quando espero que seja falso

1

ainda lutando com esse shell script (Password Validation), procurei a solução, mas ainda não encontrei a solução adequada.

#!/bin/sh

echo "enter the password"
read password

len="${#password}"

if test $len -ge 8 ; then
    echo "$password" | grep -q [A-Z]
    echo "$password" | grep -q [a-z]
    echo "$password" | grep -q [0-9]

    if test $? -eq 0 ; then
      echo "Strong password"
    else
      echo "Weak password"
    fi

else
    echo "password lenght should be greater than or equal 8"
fi

O resultado deste script foi o seguinte:

# ./password.sh 
enter the password
12345678
Strong password >> Not as I expected which is should be weak password

Onde está minha culpa?

    
por RizGuard 31.07.2016 / 18:12

3 respostas

3

Suas invocações de grep estão sendo executadas sequencialmente e $? é igual ao último grep em seu script. Você vai querer usar algo assim após cada grep :

retCodes=0
echo "$password" | grep -q "[A-Z]"
retCodes=$(($retCodes + $?))

echo "$password" | grep -q "[a-z]"
retCodes=$(($retCodes + $?))

echo "$password" | grep -q "[0-9]"
retCodes=$(($retCodes + $?))

O if [[ $retCodes -eq 0 ]]; then ...

    
por 31.07.2016 / 18:18
4

Algumas coisas:

  • Usar read sem -r dificulta ter \ na senha.

  • Não citar as expressões regulares fará com que o shell as trate como padrões de globbing e elas se expandirão para nomes de arquivos.

  • A variável $? manterá apenas o status de saída do último grep .

Considere o seguinte script bash :

#!/bin/bash

read -r -p "password:" -s password

if (( ${#password} < 8 )); then
  echo "Passwords need 8 or more characters"
  exit 1
fi

has_upcase=0
has_locase=0
has_digit=0
has_other=0

case "$password" in
  *[[:upper:]]*) has_upcase=1 ;;&
  *[[:lower:]]*) has_locase=1 ;;&
  *[[:digit:]]*) has_digit=1  ;;&
  *[^[:alnum:]]*) has_other=1 ;;
esac

if (( !has_upcase )); then
  echo "Make sure you password has at least one upper-case letter"
elif (( !has_locase )); then
  echo "Make sure your password has at least one lower-case letter"
elif (( !has_digit )); then
  echo "Make sure your password has at least one digit"
elif (( !has_other )); then
  echo "Make sure your password has at least non-alphanumeric character"
else
  echo "Your password is ok"
fi

Eu tomei a liberdade de adicionar um requisito "não alfanumérico" ao teste.

O read de bash é capaz de fornecer ao usuário um prompt e ler enquanto não está ecoando o que é digitado.

A instrução case verifica se a senha inserida contém pelo menos um caractere em maiúsculas, uma minúscula, um numérico e um não alfanumérico (usando As classes de caracteres POSIX ). O funky olhando ;;& no final de cada linha significa "continue testando o próximo padrão com esta string".

Para obter uma variante sh do POSIX, substitua o read por

stty -echo
printf "password: "
read -r password
stty echo
printf "\n"

E a declaração case com algo como

case "$password" in *[[:upper:]]*) has_upcase=1 ;; esac
case "$password" in *[[:lower:]]*) has_locase=1 ;; esac
case "$password" in *[[:digit:]]*) has_digit=1  ;; esac
case "$password" in *[^[:alnum:]]*) has_other=1 ;; esac

O resto ainda deve ser POSIX.

    
por 31.07.2016 / 18:45
0

Talvez isso ajude:

#!/bin/sh

echo "enter the password"
read -r password

caps="$(echo "$password" | sed 's/[^A-Z]//g')"
lowers="$(echo "$password" | sed 's/[^a-z]//g')"
numbers="$(echo "$password" | sed 's/[^0-9]//g')"

if [ "${#password}" -lt 8 ]; then
    echo "password lenght should be greater than or equal 8"
else
    echo "caps=${#caps} lowers=${#lowers} numbers=${#numbers}"
    if [ "${#caps}" -ge 1 ] && [ "${#lowers}" -ge 1 ] && [ "${#numbers}" -ge 1 ]; then
        echo "Strong password"
    else
        echo "Weak password"
    fi
fi
    
por 31.07.2016 / 21:43