You are correct in that the standard definition of case
does not allow for a AND operator in the pattern. You're also correct that trying to say "starts with a lower-case vowel AND starts with an upper-case vowel" would not match anything. Note also that you have your patterns & explanations reversed for the begins/ends with a digit tests -- using a pattern of [0-9]*
would match words that begin with a digit, not end with a digit.
One approach to this would be to combine your tests into the same pattern, most-restrictive first:
case $word in
([AaEeIiOoUu]??[0-9]) echo it is four characters long and begins with a vowel and ends with a digit;;
([AaEeIiOoUu]*[0-9]) echo it is not four characters long begins with a vowel and ends with a digit;;
# ...
esac
Another (lengthy!) approach would be to nest your case
statements, building up appropriate responses each time. Does it begin with a vowel, yes or no? Now, does it end in a digit, yes or no? This would get unwieldy quickly, and annoying to maintain.
Another approach would be to use a sequence of case
statements that builds up a string (or array) of applicable statements; you could even add *
catch-all patterns to each if you wanted to provide "negative" feedback ("word does not begin with a vowel", etc).
result=""
case $word in
[AaEeIiOoUu]*)
result="The word begins with a vowel." ;;
esac
case $word in
[0-9]*)
result="${result} The word begins with a digit." ;;
esac
case $word in
*[0-9])
result="${result} The word ends with a digit." ;;
esac
case $word in
????)
result="${result} You entered four characters." ;;
esac
printf '%s\n' "$result"
For examples:
$ ./go.sh
Enter a word: aieee
The word begins with a vowel.
$ ./go.sh
Enter a word: jeff42
The word ends with a digit.
$ ./go.sh
Enter a word: aiee
The word begins with a vowel. You entered four characters.
$ ./go.sh
Enter a word: 9arm
The word begins with a digit. You entered four characters.
$ ./go.sh
Enter a word: arm9
The word begins with a vowel. The word ends with a digit. You entered four characters.
Alternatively, bash extended the syntax for the case
statement to allow for multiple patterns to be selected, if you end the pattern(s) with ;;&
:
shopt -s nocasematch
case $word in
[aeiou]*)
echo "The word begins with a vowel." ;;&
[0-9]*)
echo "The word begins with a digit." ;;&
*[0-9])
echo "The word ends with a digit." ;;&
????)
echo "You entered four characters." ;;
esac
Note that I removed the *
catch-all pattern, since that would match anything & everything, when falling through the patterns this way. Bash also has a shell option called nocasematch
, which I set above, that enables case-insensitive matching of the patterns. That helps reduce redundancy -- I removed the | [AEIOU]*
part of the pattern.
For examples:
$ ./go.sh
Enter a word: aieee
The word begins with a vowel.
$ ./go.sh
Enter a word: jeff42
The word ends with a digit.
$ ./go.sh
Enter a word: aiee
The word begins with a vowel.
You entered four characters.
$ ./go.sh
Enter a word: 9arm
The word begins with a digit.
You entered four characters.
$ ./go.sh
Enter a word: arm9
The word begins with a vowel.
The word ends with a digit.
You entered four characters.
|
instead of&&
. Have in mind that the conditions are mutually exclusive: it is OR not AND.