The following script is longer than your code, but shows how you could test a string against a list of patterns. The code detects whether the string matches all patterns or not and prints out a result.
#!/bin/sh
string=TestString1
failed=false
for pattern in '*[[:upper:]]*' '*[[:lower:]]*' '*[[:digit:]]*' '*[[:punct:]]*'
do
case $string in
$pattern) ;;
*)
failed=true
break
esac
done
if "$failed"; then
printf '"%s" does not meet the requirements\n' "$string"
else
printf '"%s" is ok\n' "$string"
fi
The case ... esac
compound command is the POSIX way to test a string against a set of globbing patterns. The variable $pattern
is used unquoted in the test, so that the match is not done as a string comparison. If the string does not match the given pattern, then it will match *
, and the loop is exited after setting failed
to true
.
Running this would yield
$ sh script.sh
"TestString1" does not meet the requirements
You could tuck the testing away in a function like so (the code tests a number of strings in a loop, calling the function):
#!/bin/sh
test_string () {
for pattern in '*[[:upper:]]*' '*[[:lower:]]*' '*[[:digit:]]*' '*[[:punct:]]*'
do
case $1 in ($pattern) ;; (*) return 1; esac
done
}
for string in TestString1 Test.String2 TestString-3; do
if ! test_string "$string"; then
printf '"%s" does not meet the requirements\n' "$string"
else
printf '"%s" is ok\n' "$string"
fi
done
If you want to set LC_ALL=C
locally in the function, write it as
test_string () (
LC_ALL=C
for pattern in '*[[:upper:]]*' '*[[:lower:]]*' '*[[:digit:]]*' '*[[:punct:]]*'
do
case $1 in ($pattern) ;; (*) return 1; esac
done
)
Note that the body of the function now is in a sub-shell. Setting LC_ALL=C
will therefore not affect the value of this variable in the calling environment.
Get the shell function to take the patterns as arguments too, and you basically get Stéphane Chazelas' answer (the variant).