TheWinterSnow
TheWinterSnow

Reputation: 175

bash script testing conditionals on multiple paramters on a string

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.

Upvotes: 2

Views: 263

Answers (2)

xhienne
xhienne

Reputation: 6134

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

Upvotes: 1

cdarke
cdarke

Reputation: 44354

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.

Upvotes: 1

Related Questions