I'm trying to revive my rusty shell scripting skills, and I've run into a problem with case statements. My goal in the program below is to evaluate whether a user-supplied string begins with a capital or lowercase letter:
# practicing case statements
echo "enter a string"
read yourstring
echo -e "your string is $yourstring\n"
case "$yourstring" in
[A-Z]* )
echo "your string begins with a Capital Letter"
;;
[a-z]* )
echo "your string begins with a lowercase letter"
;;
*)
echo "your string did not begin with an English letter"
;;
esac
myvar=nope
case $myvar in
N*)
echo "begins with CAPITAL 'N'"
;;
n*)
echo "begins with lowercase 'n'"
;;
*)
echo "hahahaha"
;;
esac
When I enter a string beginning with a lowercase letter (e.g., "mystring" with no quotes), the case statement matches my input to the first case and informs me that the string begins with a capital letter. I wrote the second case statement to see if I was making some obvious syntax or logic error (perhaps I still am), but I don't have the same problem. The second case structure correctly tells me that the string held by $myvar begins with a lowercase letter.
I have tried using quotes to enclose $yourstring in the first line of the case statement, and I've tried it without quotes. I read about the 'shopt' options and verified that 'nocasematch' was off. (For good measure, I toggled it on and tried again, but I still didn't get the correct result from my first case statement.) I've also tried running the script with sh and bash, but the output is the same. (I call the shell explicitly with "sh ./case1.sh" and "bash ./case1.sh" because I did not set the execution bit. Duplicating the file and setting the execution bit on the new file did not change the output.)
Though I don't understand all of the output from running the shell with the '-x' debug option, the output shows the shell progressing from the first "case" line to execution of the command following the first pattern. I interpret this to mean that the first pattern was a match for the input string, but I am uncertain why.
When I switch the order of the first two patterns (and corresponding commands), the case statement succeeds for lowercase letters but incorrectly reports "MYSTRING" as beginning with lowercase letters. Since anything alphabetic is detected as matching whichever pattern appears first, I think I have a logical error...but I'm not sure what.
I found a post by "pludi" on unix.com in which it is advised that "the tests for lowercase and upper case characters were [a-z] and [A-Z]. This no longer works in certain locales and/or Linux distros." (see https://www.unix.com/shell-programming-and-scripting-128929-example-switch-case-bash.html) Sure enough, replacing the character ranges with [[:upper:]] and [[:lower:]] resolved the problem.
I'm on Fedora 31, and my locale output is as follows:
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
I'd like to know whether I'm not understanding character ranges, or not understanding how pattern matching works in case statements, or if the underlying shell capabilities changed (and why?). If anyone has the patience, I would greatly appreciate an explanation; I'm also happy to read relevant documentation. Thanks!
locale
)? Also, how do you run the script? There is no#!
-line at the top of the script so the shell that is use to run it will depend on your interactive shell, unless you run it with an explicit interpreter on the command line.