70

How to export a variable which has dot in it. I get 'invalid variable name' when I tried :

 export my.home=/tmp/someDir
-ksh: my.home=/tmp/someDir: invalid variable name

Even escaping metacharacter dot (.) din't helped either

$ export my\.home=/tmp/someDir
export: my.home=/tmp/someDir: is not an identifier
2

4 Answers 4

82

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.

2
  • It is because of in integration of ant . And unfortunately it does not allow to set/export variable from unix. Accepting your answer. .. Oct 4, 2013 at 7:40
  • 2
    ant is usually configured by a single environment variable called ANT_OPTS or by ~/.antrc. No need for strange environment variable names for ant itself.
    – michas
    Oct 4, 2013 at 11:18
12

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 like es and akanga 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 and zsh (also bash 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 fool zsh or ksh 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 how zsh 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)).

1
  • 1
    mksh (and pdksh) indeed construct the environment processes they spawn get completely from scratch, using only those parameters exported in the current shell execution environment, so there is no way to pass those variables through those shells. (Note that the variables that are passed are subject to change; e.g. I’m planning to support array exports for mksh some day.)
    – mirabilos
    Feb 27, 2014 at 14:10
2

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.

1
0

The answer from @michas is quite correct, but it's possible to extend it to simulate export function with dot environment names.

To "export" such variable, you can exec current shell with env command. E.g. to export test.env=foo variable, use:

exec env "test.env=foo" $SHELL

Exec will replace current shell with a new process, where the new process will be a new instance of current shell ($SHELL) with additional environment variable test.env (added by env "test.env=foo"). So after this command you can access it from your process, e.g.:

perl -e 'print $ENV{"test.env"}'
1
  • I fail to see how this improves on that other answer as both seem to say the same thing (the only difference is that you use exec to replace the current shell rather than to start a new shell session as a child process). Also note that $SHELL generally is the login shell of the current user, which may differ from the current shell.
    – Kusalananda
    Mar 9 at 12:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .