45

I am not able to use - in variables in shell. Is there a way to be able to use it, because I have one script which depends on such named variables:

$export a-b=c
-bash: export: `a-b=c': not a valid identifier

$export a_b=c

First throws the given error and second works fine.

10 Answers 10

53

I've never met a Bourne-style shell that allowed - in a variable name. Only ASCII letters (of either case), _ and digits are supported, and the first character must not be a digit.

If you have a program that requires an environment variable that doesn't match the shell restrictions, launch it with the env program.

env 'strange-name=some value' myprogram

Note that some shells (e.g. modern dash, mksh, zsh) remove variables whose name they don't like from the environment. (Shellshock has caused people to be more cautious about environment variable names, so restrictions are likely to become tighter over time, not more permissive.) So if you need to pass a variable whose name contains special character to a program, pass it directly, without a shell in between (env 'strange-name=some value' sh -c'…; myprogram' may or may not work).

| improve this answer | |
  • No longer works. – Jesse Glick Feb 9 '17 at 21:00
  • 4
    @JesseGlick Yes it does. (Your comment would be useful if you defined “not working”: with what data? what is the effect instead of the desired effect? and if you said which implementation of env you used on what operating system.) – Gilles 'SO- stop being evil' Feb 9 '17 at 21:17
  • Sorry. Ubuntu Yakkety with all updates, env from coreutils, sh from dash: env 'with-dashes=value' bash -c 'env | fgrep dashes' works but env 'with-dashes=value' sh -c 'env | fgrep dashes' prints nothing. That is, env itself is fine, but Dash seems to specifically block these variables. Thus if the program in question is launched via a shell wrapper with a typical #!/bin/sh header, there is no apparent way to pass in such variables. example workaround – Jesse Glick Apr 14 '17 at 12:23
  • @JesseGlick That's dash removing the variable. You have to use env closer to the calling site of the program that needs this variable name, without a shell in between. Dash isn't alone in removing variables whose name it doesn't like. – Gilles 'SO- stop being evil' Apr 14 '17 at 13:05
  • 1
    @JesseGlick It's true that some things that used to work might no longer work, though: since shellshock, people have become more conservative about variable names, and dash did in fact change since I wrote this answer (not as a consequence of Shellshock though, but to avoid a bug along the same lines). I've added a note to my answer. – Gilles 'SO- stop being evil' Apr 14 '17 at 13:10
16

That's not possible in Bash.

From the Definitions section in the manual page of bash:

name A word consisting only of alphanumeric characters and underscores, and beginning with an alphabetic character or an underscore. Also referred to as an identifier.

From the Parameters section in the manual page of bash:

A parameter is an entity that stores values. It can be a name, a number, or one of the special characters listed below under Special Parameters. A variable is a parameter denoted by a name.

| improve this answer | |
  • 2
    +1 for demonstrating the usefulness of man pages once more – ktf Oct 31 '11 at 11:48
  • 2
    Old post I know but, I want to point out that to newcomers man pages can be quite cryptic. I still have times when I need hunt down better explanations/examples. Anyone would be lying if they said it never happened to them. – TCZ8 Dec 17 '14 at 15:08
  • 1
    @TCZ8 The only people that have told me they thought man pages were 'cryptic' are the same sort of people that don't read error messages and just skim read everything, skipping right over what they need to read. – Miles Rout Jan 24 '17 at 22:49
13

You can access a hyphenated variable using an indirect reference.

$ env 'my-hyphenated-variable=hello' /bin/bash
$ name='my-hyphenated-variable'
$ echo ${!name}
hello
| improve this answer | |
  • 1
    I had never heard of this functionality until reading this comment.Provided a much easier solution for me than the accepted answer. – DrStrangepork Aug 26 '15 at 15:03
  • 9
    This behavior has been disabled in newer versions of bash. See stackoverflow.com/questions/36989263/… for a thorough analysis of the situation. – Nicolas Dudebout Sep 15 '16 at 2:16
6

If your script depends on having variable names have hyphens, that's a programming error. If it is convenient for you because of the tools that you regularly use to have the variable names contain a hyphen, you may have to learn more and different tools.

Have you tried using tr to convert the hyphens into underscores?

hyphenated_name="a-b"
unhyphenated_name=$(echo $hyphenated_name | tr '-' '_')
declare -x $unhyphenated_name="some value"

Bash does allow '-' to appear in function names. I do this all the time. For example:

function foo-bar() {
   echo "$@"
}
| improve this answer | |
3

The Bash manual defines a "name" as:

A 'word' consisting solely of letters, numbers, and underscores, and beginning with a letter or underscore. 'Name's are used as shell variable and function names. Also referred to as an 'identifier'.

So you can't use a hyphen in a name.

| improve this answer | |
2

The dash (-) character is a break character and not allowed as part of variable names. There are ways to hack this with quoted variables, but the parsing of it is really problematic. There are also other characters with special meanings in the context of variable names in bash, notably braces, parenthesis, operator characters and quotes. (e.g. {}()=+-&'" and more)

I would suggest that practically you need to find another paradigm on which to build your script. You might have a hang over idea from other languages about "variable variable names". This is generally not a good idea in shell scripts.

If you edit this or ask a new question with details of your context and what you are trying to accomplish we might be able to suggest a good way to script it.

| improve this answer | |
0

Most shells only support a-z, A-Z, 0-9 and _ for variablenames. Read second item in this page.

| improve this answer | |
0

You can play with env and sed.

As an example, I needed to read this variable 'ELASTICSEARCH_CLUSTER-NODES'.
The env command output this :

~ $ env
ELASTICSEARCH_CLUSTER-NODES=elasticsearch:9200
JAVA_ALPINE_VERSION=8.212.04-r0
HOSTNAME=17eb9e7fec4c
...

So to extract the variable :

ESHOST=`env | sed -n 's/ELASTICSEARCH_CLUSTER-NODES=\(.*\)/\1/p'`
| improve this answer | |
-1

I believe that only letters, numbers, and underscore are allowed for bash variables. This is the case in many programming languages (javascript being an exception).

I recommend not having your script depend on those types of variable names.

In fact, you should try to program in such a way that you can replace variable names with other names and it doesn't make a difference. In general, variable names should describe what the variable contains. This makes it much easier to debug; if not for you, then for the next developer that is trying to figure out the code.

| improve this answer | |
-1

You can use the env command to set and unset environment variables with hiphens "-".

To set you must use env to run your command: env command. You pass variables this way:

env a-b=c command

See it working with:

env a-b=c env

or to make it clearer:

env a-b=c env|grep 'a-b'
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.