2

I am working on a bash shell script that tests a string and returns true for the following:

1) Has a minimum of 8 characters

2) Has at least one letter and one number

3) Has both a lowercase and uppercase letter

Through searching I did find how to get the number of characters in a string

srtLen=$(echo -m $str | wc -m)

And the if statement would be

if [ $strLen -ge 8 ]; then
  #make bool var true
fi

But I cannot find how to test and return a boolean for if a string has a lower case letter, an uppercase letter and at least one number. I don't care if each test is separate and I imagine they would be in separate if statements which is why I have mentioned in the code above a boolean variable that will be set based on the conditions.

7
  • 2
    str="foo"; echo "${#str}" Commented Oct 13, 2018 at 9:05
  • Is "one letter" in the English alphabet, or what? Commented Oct 13, 2018 at 9:25
  • 1
    It can be any letter English alphabet or other alphabet. For the most part for simplicity sake maybe the English alphabet. Commented Oct 13, 2018 at 9:27
  • Any other alphabet requires Unicode which bash does not support. Commented Oct 13, 2018 at 9:34
  • 1
    This reeks of a password policy check. If so, the person providing requirements should read Peter Gutmann's Engineering Security before you go further. He dedicates an entire chapter to passwords and debunking stupid practices like masks and requiring a letter, number and symbol. Commented Oct 14, 2018 at 0:37

2 Answers 2

1

Here is a generic answer that will work with non-English locale and multi-byte UTF-8 characters.

Let us translate each of your requirements into bash code:

  1. $str as a minimum of 8 characters: this can be done in several simple ways using bash builtins

    • [ "${#str}" -ge 8 ] && echo "str has a minimum of 8 characters"

      Straightforward: we compare the length of $str

    • [[ "$str" == ????????* ]] && echo "str has a minimum of 8 characters"

      $str is checked against a pattern that matches at least 8 characters

    • [[ "$str" =~ .{8} ]] && echo "str has a minimum of 8 characters"

      $str is checked against a regular expression that matches an 8 character string

    • [ -n "${str#???????}" ] && echo "str has a minimum of 8 characters"

      We check that $str is not empty when the first 7 characters are removed (not obvious, should be avoided)

  2. Has at least one digit:

    • [[ "$str" == *[[:digit:]]* ]] && echo "str has at least one digit"

      $str is checked against a pattern that matches a digit surrounded by any number of characters

    • [[ "$str" =~ [[:digit:]] ]] && echo "str has at least one digit"

      $str is checked against a regular expression that matches a single digit

    • [ -n "${str//[^[:digit:]]}" ] && echo "str has at least one digit"

      We check that $str is not empty when all non-digit characters are removed (not obvious, should be avoided)

  3. Has at least one lowercase letter:

    Same as for the digit, just replace [[:digit:]] with [[:lower:]]

    [[ "$str" == *[[:lower:]]* ]] && echo "str has at least one lowercase letter"
    [[ "$str" =~ [[:lower:]] ]] && echo "str has at least one lowercase letter"
    [ -n "${str//[^[:lower:]]}" ] && echo "str has at least one lowercase letter"
    
  4. Has at least one uppercase letter:

    Same as for the digit, just replace [[:digit:]] with [[:upper:]]

    [[ "$str" == *[[:upper:]]* ]] && echo "str has at least one uppercase letter"
    [[ "$str" =~ [[:upper:]] ]] && echo "str has at least one uppercase letter"
    [ -n "${str//[^[:upper:]]}" ] && echo "str has at least one uppercase letter"
    

You can of course combine the four conditions:

$ str='my ßtrÎñ9'
$ if [[ "${#str}" -ge 8 \
    && "$str" =~ [[:digit:]] \
    && "$str" =~ [[:lower:]] \
    && "$str" =~ [[:upper:]] \
  ]]; then
      echo "str is a valid password"
  else
      echo "str is NOT a valid password"
  fi

str is a valid password
Sign up to request clarification or add additional context in comments.

Comments

1

This is for the English alphabet, if you need others then you need to mess with the locale and the variable LC_COLLATE:

check_str()
{   
    str="$1"

    # Has a minimum of 8 characters
    if (( ${#str} > 7 )) &&

       # Has at least one number
       [[ "$str" = *[0-9]* ]] &&

       # Has both a lowercase 
       [[ "$str" = *[a-z]* ]] &&
       # and uppercase letter
       [[ "$str" = *[A-Z]* ]]
    then
        return 0
    else
        return 1
    fi
}

while :
do
    read -p "Enter a string: " inp
    if check_str "$inp"
    then
        echo "$str matches"
    else
        echo "$str does not match"
    fi
done

Test run:

Enter a string: helloHHx
helloHHx does not match
Enter a string: helloH1x
helloH1x matches
Enter a string: 12345678
12345678 does not match
Enter a string: hello
hello does not match
Enter a string: now is The 4 time for all good men
now is The 4 time for all good men matches

Note that your criteria 2 and 3 overlap, for 2 we only need check if there is a number, presence of a letter is checked in 3.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.