String comparison in most programming languages is case-sensitive. That means that the string 'A'
and 'a'
are considered different. Humans usually don’t think that way, so there is bound to be trouble and confusion.
If you are looking at single letters, the bracket expansion can be quite useful:
case $input in
[aA])
# handle 'a'
;;
[bB])
# handle 'b'
;;
[qQ])
# handle 'q': quit
exit 0
;;
*)
echo "Option is not available. Please try again"
;;
esac
However, for longer strings the bracket expansion gets cumbersome. To cover all case combinations of the word cat
you need [cC][aA][tT]
. For longer, or unknown strings, it is easier to convert a string to uppercase (all capitals) or lower case before comparing.
sh and bash3
Bash3 and sh have no built-in means to convert case of a string, but you can use the tr
tool:
name="John Doe"
# sh
echo $(echo "$name" | tr '[:upper:]' '[:lower:]' )
john doe
# bash3
echo $(tr '[:upper:]' '[:lower:]' <<< "$name")
john doe
Switch the [:upper:]
and [:lower:]
arguments to convert to upper case.
There are many other tools available that can provide this functionality, such as awk
or sed
.
Bash 5
Bash 5 has a special parameter expansion for upper- and lowercasing strings:
name="John Doe"
echo ${name,,}
john doe
echo ${name^^}
JOHN DOE
Zsh
In zsh you can use expansion modifiers:
% name="John Doe"
% echo ${name:l}
john doe
% echo ${name:u}
JOHN DOE
You can also use expansion flags:
% name="John Doe"
% echo ${(L)name}
john doe
% echo ${(U)name}
JOHN DOE
In zsh you can even declare a variable as inherently lower case or upper case. This will not affect the contents of the variable, but it will automatically be lower- or uppercased on expansion:
% typeset -l name
% name="John Doe"
% echo $name
john doe
% typeset -u name
% echo $name
JOHN DOE
I like your Bash5 suggestion, but it does not work for me:
$ name=”John Doe”
$ echo ${name,,}
-bash: ${name,,}: bad substitution
$ bash –version
GNU bash, version 5.0.16(1)-release (x86_64-apple-darwin18.7.0)
It works for me… check your syntax for weird characters?
I copy-pasted your example. But just to be safe, I just re-typed it and encounter the same problem. (Indeed, I found your page because I’ve had this problem and have been searching for answers.) Even this simple example always fails. As noted in my original comment, I am using Bash5 on MacOS Mojave,
[MacOS:~]$ name=”John Doe”
[MacOS:~]$ echo ${name,,}
-bash: ${name,,}: bad substitution
[MacOS:~]$ echo ${name^^}
-bash: ${name^^}: bad substitution
[MacOS:~]$
what do you get when you run
echo $BASH_VERSION
?Interesting. Different than what I get when I run bash –version
[MacOS:~]$ echo $BASH_VERSION
3.2.57(1)-release
[MacOS:~]$ bash –version
GNU bash, version 5.0.16(1)-release (x86_64-apple-darwin18.7.0)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
[MacOS:~]$
Yes, so you installed bash 5. The bash v5 binary is (probably) installed at /usr/local/bin/bash. Since /usr/local/bin is in the default PATH before /bin your shell picks up the new bash before the original /bin/bash. That is why bash —version returns 5
However, your default shell, the one that starts when you open a Terminal window is still the built-in /bin/bash (v3.2)
I explain this here: https://scriptingosx.com/2019/02/install-bash-5-on-macos/
Ahah. I see. Frustrating.
I care more about scripting than my Terminal shell… so I will need to think about whether to use the ‘env’ method or hard-coding the path to bash5 in my shebang.
Thank you.