You can assign values to variables (with
var=value). There's a fine distinction between a parameter and a variable:
A parameter is an entity that stores values. It can be a name, a number, or one of the special characters listed below. A variable is a parameter denoted by a name.
and a name is defined as:
A word consisting solely of letters, numbers, and underscores, and beginning with a letter or underscore. Names are used as shell variable and function names. Also referred to as an identifier.
(That's the definition in Bash's manual, POSIX probably has something similar.)
So, anything that matches the regex
[a-zA-Z_][a-zA-Z_0-9]* (assuming ASCII character ranges) is a valid name for a variable. Unicode characters and punctuation don't work.
That's pretty much the set of characters supported in variable names in most programming languages, though some do support Unicode, too. Words beginning with digits are taken as numbers (note that stuff like
123e3 are often valid numbers), and the dash is usually taken as the minus operator, so
a-b is a simple arithmetic operation of two variables, not one variable. And so on.
The parameters that aren't of that format are the numbered positional parameters (script/function arguments, assignable with
set) and the special parameters. Note that
_ (a single underscore) is one of the latter, and while you can assign to it without an error, it's not much use since it resets immediately.
These are fine:
$ a123=foo __=bar
$ echo $a123 $__
$ _=foo echo bar >/dev/null
$ echo $_
As for the uppercase ones, there's a list of the variables that are special to Bash or other Bourne-ish shells (ignore the readline variables, they're not related here). They all do seem to start with an uppercase letter, except that there's
histchars that's all lowercase(!). Luckily, it only matters if history expansion is enabled.