175

What characters are allowed in Linux environment variable names? My cursory search of man pages and the web did only produce information about how to work with variables, but not which names are allowed.

I have a Java program that requires an defined environment variable containing a dot, like com.example.fancyproperty. With Windows I can set that variable, but I had no luck setting it in linux (tried in SuSE and Ubuntu). Is that variable name even allowed?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Christian Semrau
  • 8,913
  • 2
  • 32
  • 39
  • 3
    Luckily, I found that the program is just as happy with a Java system property (declared with a `-D` command line option), so it works now. Obviously the program looks in both variable sets without telling me. But still I am curious about which environment variable names are allowed. – Christian Semrau May 12 '10 at 17:04
  • @AleksandrDubinsky I deleted it. This is similar but about alias definition not exactly environment variables http://stackoverflow.com/questions/24690640/which-characters-are-allowed-in-a-bash-alias#answer-32707048 – Lime Feb 21 '16 at 03:58
  • 2
    If you're using **Spring**, then the default SystemEnvironmentPropertySource will also look up `com_example_fancyproperty` and `COM_EXAMPLE_FANCYPROPERTY`. – Aleksandr Dubinsky Feb 21 '16 at 13:44

8 Answers8

243

From The Open Group:

These strings have the form name=value; names shall not contain the character '='. For values to be portable across systems conforming to IEEE Std 1003.1-2001, the value shall be composed of characters from the portable character set (except NUL and as indicated below).

So names may contain any character except = and NUL, but:

Environment variable names used by the utilities in the Shell and Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase letters, digits, and the '_' (underscore) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names.

So while the names may be valid, your shell might not support anything besides letters, numbers, and underscores.

Robert Gamble
  • 106,424
  • 25
  • 145
  • 137
  • After reading the citation of 1003.1-2001, I'll just stick to UPPERCASE, 0-9 digits & the _ (underscore) characters for compatibility. – checksum Feb 20 '13 at 16:07
  • so for best compatibility and some flexibility, basically use only: "letters, numbers, and underscores" like in `[[:alnum:]_]*`, thx! and bash seems not to accept vars begining with numbers either – Aquarius Power Jul 06 '14 at 04:26
  • 13
    Just checking: the second quote is non-normative: it just observes that the variables that POSIX defines as special for it's utilities are `[a-zA-Z_][a-zA-Z0-9_]*` (implicitly suggesting this form is saner), but the actual spec (quote 1) **requires** all implementation to support anything but `=` and `NUL`? – Ciro Santilli OurBigBook.com Aug 21 '14 at 20:13
  • 3
    Also, the "portable character set" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap06.html#tagtcjh_3 contains stuff like spaces and non-printables: so can we use those things or not? – Ciro Santilli OurBigBook.com Aug 21 '14 at 20:19
  • 3
    This is exactly what I observe. Shell doesn't like special characters as a part of a variable name. However when one program or script (e.g. java or perl) initializes a variable with special characters in its name and calls another executable (a child process) the latter executable can access that variable without problems. – oᴉɹǝɥɔ May 14 '15 at 20:18
  • 2
    @checksum, UPPERCASE is explicitly specified for variable names with meaning to POSIX-specified tools, including the shell; names with at least one lower-case character are explicitly reserved for application use. Thus, best practice is actually to include at least one lower-case character in your applications' variable names to ensure that you aren't unintentionally overwriting (as setting a shell variable will overwrite any like-named environment variable) a variable with meaning to the system. See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html – Charles Duffy Mar 24 '17 at 15:53
  • 2
    @CiroSantilli烏坎事件2016六四事件法轮功, you can use them in environment variables; you *can't* use them in shell variables, and those environment variables aren't guaranteed to be accessible from the shell. – Charles Duffy Mar 24 '17 at 15:54
50

The POSIX standards on shells section of IEEE Std 1003.1-2008 / IEEE POSIX P1003.2/ISO 9945.2 Shell and Tools standard doesn't define the lexical convention for variable names, however a cursory look at the source reveals it uses something similar to

[a-zA-Z_]+[a-zA-Z0-9_]*

(Edit: Added missing underscore in 2nd character class.)

A quick note, as some shells don't support the + in regex, a potentially more portable regex may be:

[a-zA-Z_]{1,}[a-zA-Z0-9_]{0,}

Nick Bull
  • 9,518
  • 6
  • 36
  • 58
Aiden Bell
  • 28,212
  • 4
  • 75
  • 119
  • 6
    Thanks, Aiden. I think there is an underscore missing in the second set of square brackets: It should probably read: `[a-zA-Z_][a-zA-Z0-9_]*` For those like me who find the reference to bash-4.1 a little vague (616'000 lines of code), here are a few hints to find the relevant lines of code: `subst.c: param_expand(), in the default case` -> `general.h:` /* Define exactly what a legal shell identifier consists of. */ #define legal_variable_starter(c) (ISALPHA(c) || (c == '_')) #define legal_variable_char(c) (ISALNUM(c) || c == '_') – Chris Dec 05 '10 at 20:11
  • 6
    You do not need that plus in the first character class. – scravy Sep 03 '14 at 18:40
  • 3
    @scravy true, though I took the regexp from the source so i'm gonna keep the + in. – Aiden Bell Sep 06 '14 at 13:20
  • 6
    POSIX defines: [3.231 Name](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_231) `a word consisting solely of underscores, digits, and alphabetics from the portable character set. The first character of a name is not a digit`. –  Nov 19 '15 at 06:56
  • Not in the shell section, but there absolutely are POSIX standards that include conventions for environment variable naming (and actually discuss names that are reserved for shell use). See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html – Charles Duffy Mar 24 '17 at 15:55
  • It's quite interesting why the actual source code includes a quite unnecessary `+` there. – Artfaith May 05 '22 at 15:50
16

My quick testing showed that they basically follow the same rules as C variable names do have, namely

  1. a-z, A-Z, _ and 0-9
  2. May NOT begin with a number

So this excludes . inside them. Any illegal variable name is credited with unknown command.

This was tested in ZSH, which is mostly BASH-compatible.

Captain Man
  • 6,997
  • 6
  • 48
  • 74
LukeN
  • 5,590
  • 1
  • 25
  • 33
11

YES, YOU CAN DO IT.

Use exec and env command to implement this scene.

Test Fixture in Docker

docker run -it --rm alpine:3.10

Run command in container:

exec env spring.application_name=happy-variable-name ${SHELL:-/bin/sh}

Verify environment variables:

HOSTNAME=bd0bccfdc53b
SHLVL=2
HOME=/root
spring.application_name=happy-variable-name
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/

Use ps aux to verify PID not changed

PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
   12 root      0:00 ps aux

Use python to verify environemnt variable

apk add python
python -c 'import os; print(os.environ["spring.application_name"])'

OUTPUT is happy-variable-name.

What happen?

  1. Shell call builtin exec
  2. Shell builtin exec call syscall.exec create process 'env' to replace current shell
  3. env process call syscall.execvp create process '/bin/sh' to replace env process

Another way

  • Docker image

If you are using docker, you can set variable in Dockerfile

FROM busybox
ENV xx.f%^&*()$#ff=1234
  • Kubernetes configmap

If you are using kubernetes, you can set variable by ConfigMap

test.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: foo-config
data:
  "xx.ff-bar": "1234"

---
apiVersion: v1
kind: Pod
metadata:
  name: foobar
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/busybox
      command: [ "/bin/sh", "-c", "env" ]
      envFrom:
      - configMapRef:
          name: foo-config
  restartPolicy: Never

Deploy pod kubectl apply -f test.yaml

Verify kubectl logs foobar output:

xx.ff-bar=1234

ConfigMap allow '-', '_' or '.'

Zealic
  • 1,535
  • 1
  • 10
  • 6
7

Depends on what you mean by 'allowed'.

Ignoring Windows for the nonce:

The environment is an array of strings, passed to the main function of a program. If you read execve(2), you will see no requirements or limits on these strings other than null-termination.

By convention, each string consists of NAME=value. There is no quoting convention, so you can't have an '=' in the name in this convention.

Normal humans set these strings by discussing them with their shell. Each shell has it's own ideas of what are valid variable NAMEs, so you have to read the man page for the shell-of-the-moment to see what it thinks.

Generally, things like com.baseball.spit=fleagh are Java system properties, and whether or not some Java program is willing to fall back to the environment, it's better to specify them with -D.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • I should have earlier come to the conclusion that the variable is formatted like a Java system property, instead of trying to set it as an environment variable. – Christian Semrau May 12 '10 at 18:44
5

It depends on the shell. I'm guessing you're using bash by default, in which case letters, numbers and underscores are allowed, but you can't start the variable name with a number. As of Bash v.3, periods are not allowed within variable names.

ire_and_curses
  • 68,372
  • 23
  • 116
  • 141
2

While most shell will not allow setting enviroment variables (as mentioned in other answers), if you have need you can execute other programs with nonstandard enviroment variables using env(1).

For example, erasing all enviroment and setting Strange.Env:Var to value foo, and executing perl program that prints it:

env -i Strange.Env:Var=foo perl -MData::Dumper -E 'say Dumper(\%ENV)'

will print

$VAR1 = {
          'Strange.Env:Var' => 'foo'
        };
Matija Nalis
  • 678
  • 1
  • 17
  • 30
0

While editing systemd service vars with systemctl edit <service_name> I can use all symbols excluding " = \ $ like:

[Service]
Environment="TOKEN=~'+*^,j-;H@[J;;G,g&xG:eH)RfK@I&fjjgdZ|IXKm]-[C"

And this works without problems.