Exporting a variable with dot (.) in it
At least for bash
the man page defines the export syntax as:
export [-fn] [name[=word]] ...
It also defines a "name" as:
name A word consisting only of alphanumeric characters and under‐
scores, and beginning with an alphabetic character or an under‐
score. Also referred to as an identifier.
Hence you really cannot define a variable like my.home
as it is no valid identifier.
I am very sure your ksh has a very similar definition of an identifier and therefore does not allow this kind of variables, too. (Have a look at its man page.)
I am also very sure there is some kind of general standard (POSIX?) specifying, what is allowed as an identifier (and therefore a variable name).
If you really need this kind of variable for some reason you can use something like
env "my.home=/tmp/someDir" bash
to define it anyway. But then again, you will not be able to access it using normal shell syntax. In this case you probably need another language like perl:
perl -e 'print $ENV{"my.home"}'
For example
env "my.home=/tmp/someDir" perl -le 'print $ENV{"my.home"}'
should print your path.
While environment variables can have any name (including the empty string) not containing an equal sign or a null byte, shells map environment variables to shell variables and in most shells, variable names are limited to ASCII alphanumerical characters and _
where the first character can't be a digit (except for the positional parameters and other special ones like $*
, $-
, $@
, …, (which are not mapped to the corresponding environment variables)). Also note that some variables are reserved/special by/to the shell.
Exceptions to that:
The
rc
shell and its derivatives likees
andakanga
support any name except the empty string, and those that are all-numeric or contain=
characters (and always export all their variables to the environment, and beware of special variables like*
,status
,pid
...):; '%$£"' = test ; echo $'%$£"' test ; '' = x zero-length variable name ;
However, it uses its own encoding for variables whose name don't contain alnums or for arrays when passed in the environment of commands being executed:
$ rc -c '+ = zzz; __ = zzz; a = (zzz xxx); env' | sed -n /zzz/l __2b=zzz$ __5f_=zzz$ a=zzz\001xxx$ $ env +=x rc -c "echo $'+'" x $ env __2b=x rc -c "echo $'+'" x
AT&T
ksh
,yash
andzsh
(alsobash
but only for single-byte characters) support alnums in the current locale, not only ASCII ones.$ Stéphane=1 $ echo "$Stéphane" 1
In those shells, you could change the locale to consider most characters as alpha, but still that wouldn't work for ASCII characters like
.
. You can foolzsh
orksh
into thinking£
is a letter, but not that.
or any other ASCII character (where allowing characters in variable names is concerned, not for the[[:alpha:]]
glob for instance).ksh93
has special variables whose name contains a dot like${.sh.version}
, but those are not mapped to environment variables and are special. The.
is to make sure it doesn't conflict with other variables. If it had chosen to call it$sh_version
, then it could have potentially broken scripts that used that variable already (see for instance howzsh
has issues with its$path
or$commands
special array/hash variables (a la csh) that break some scripts).
Note that in addition to shells not supporting those variables, some shells like pdksh/mksh do remove them from the environment they receive (bash
removes the one with an empty name, ash
, ksh
and bash
remove those environment strings that don't contain a =
character):
$ env %%%=test 1=%%% a.b=%%% mksh -c env | grep %%%
$ env %%%=test 1=%%% a.b=%%% bash -c env | grep %%%
%%%=test
a.b=%%%
1=%%%
$ perl -le '$ENV{""}="%%%"; exec "bash", "-c", "env"' | grep %%%
$ perl -le '$ENV{""}="%%%"; exec "zsh", "-c", "env"' | grep %%%
=%%%
$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
execve("/bin/ash",a,e);}'|tcc -run - | grep %%%
$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
execve("/bin/zsh",a,e);}'|tcc -run - | grep %%%
%%%
To sum up, best is to stick with variable names supported by most shells and even try to use upper case for environment variables (and lower case or mixed case for not-exported shell variables) avoiding those that are special in shells (like IFS
, PS1
, BASH_VERSION
...).
If you do need to set such a variable in a shell that doesn't support them, but doesn't discard them, you can either reexecute yourself, with something like:
#! /bin/ksh -
perl -e 'exit 1 unless defined($ENV{"a.b"})' || exec env a.b=%%% "$0" "$@"
(obviously, if you need to do it in the middle of the script, that won't help, but you could then have a look at that approach to save and restore the shell execution environment over a re-exec). Or try the debugger approach:
gdb --batch-silent -ex 'call putenv("a.b=%%%")' --pid="$$"
(that one seems to work with zsh
, yash
, csh
and tcsh
on Linux amd64, but not with any of the other shells I tried (mksh
, ksh93
, bash
, dash
)).
As the other posts point out, the most common shells do not allow for setting environment variables with periods in the name. However, I have found situations, particularly involving Docker and invoked programs, where the software required key values with periods.
However, in each of these situations, those key-value pairs could be passed to the program through other means than just environment variables. For example, in Ant, you can use the "-propertyfile (filename)" to pass in a property file formatted collection of key-values. Confd allows for "-backend file -file (yaml file)".
I passed the environment variables in the form "C__any_value='my.property.key=the value'". I then switched the program invocation to first generate the file:
set | awk -- 'BEGIN { FS="'\''" } /^C__/ {print $2}' > my-key-values.txt
The set
command, in Borne Shell, will output each property on a separate line in the form
C__any_value='my.property.key=the value'
The awk
command will process only the environment variables starting with C__
, then extract the values contained in the single quotes.
This method requires the environment variable value to be set in the precise form that the processing program requires. Additionally, if your property value or key will contain single quotes, then you will need to change the awk field separator character to something you know that won't appear, and surround the value with that character. For example, to use %
as the separator:
$ C__1="%my.key=the'value%"
$ set | awk -- 'BEGIN { FS="%" } /^C__/ {print $2}'
my.key=the'"'"'value
(the precise output will depend on your shell.) You will need to take extra steps to decode the quote escaping.