Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

E.g. next script will print Hello due to ${! rule.

A=B
B=Hello
echo ${!A}

But how can I set value to variable with indirect name? Straightforward use of ! sign doesn't work:

A=B
!A=Hello # here is tricky line
echo $B

I know there is a trick with using temp file, but I'm interested in using indirection, not something like

A=B
echo "$A=Hello" > 1.tmp
. 1.tmp
echo $B
share|improve this question
2  
eval $A=foobar –  forcefsck Mar 18 '13 at 16:32
    
Do you want to create synonyms so that both variables point to the same data? In other words when one changes, changes the other? I'm not sure I get your intention here. –  Christian Mar 18 '13 at 16:37
    
no, I just wanted to set one variable through value of another once –  Sergey Grinev Mar 18 '13 at 16:44

3 Answers 3

up vote 2 down vote accepted

Another way you could try:

$ A=B
$ read $A <<< 81
$ echo "$B"
81

But there is a security risk (!) as with all these methods (also declare / typeset and of course eval) .. In this case one must control the lefthand side (the value of $A), in other words, at least in bash, variable $A should not contain user controlled input, for example an input file, etcetera...


If your shell does not support a here-string ( <<< ) you could also use a here-document instead:

A=B
read $A << EOF
82
EOF
echo "$B"
share|improve this answer
    
wow, but why does it work? –  Sergey Grinev Mar 18 '13 at 16:47
1  
The shell expands variable $A before the read command.. –  Scrutinizer Mar 18 '13 at 17:08
    
The only issue: it doesn't work on Solaris –  Sergey Grinev Mar 18 '13 at 18:05
1  
You could try a here-document instead of a here-string, see the edit in my post.. –  Scrutinizer Mar 18 '13 at 20:13
1  
This is not a good method. It's complex, and it breaks if there are special characters in the value (newlines, backslashes and leading or trailing whitespace on a line are problematic). –  Gilles Mar 19 '13 at 0:18

You can do this with the typeset builtin:

$ A=B
$ typeset $A=42
$ echo $B
42

Or using declare:

$ declare $A=1
$ echo $B
1
share|improve this answer
    
In bash, typeset is obsolete and its replacement is declare. They are more or less identical. –  jw013 Mar 18 '13 at 16:34
    
typeset is a bit more portable though (works in ksh) –  Mat Mar 18 '13 at 16:36
    
thanks! Can't decide which answer is better. Flipped a coin :) –  Sergey Grinev Mar 18 '13 at 20:21

Following on indirection when getting the value of a variable

The portable way is to use eval. You do have to pay attention to the quoting so that special characters in the value are not evaluated when they shouldn't be. The easiest way is to store the new value in an intermediate variable and assign the value of that variable.

A=B
tmp='stuff with special characters or whatever…'
eval $A=\$tmp

The argument to eval is B=$tmp, a straightforward assignment. You don't need double quotes around $tmp even if it contains whitespace or globbing characters, because those are not expanded in an assignment.

If you want to make an environment variable, you can use export. In bash or ksh or zsh, you can use typeset to make a local variable (declare is synonymous in bash). Again, you should use an intermediate variable so that special characters are not mangled. Note that except in zsh, you need to put double quotes around the variable expansion, because this is not an assignment but a builtin that takes an argument that happens to look like an assignment.

export $A="$tmp"
share|improve this answer
    
This (using eval) is the correct answer. It's portable, adheres to the POSIX standard, and is the one used all over the place in more advanced shell scripts. One thing, though: using export on the same line as the assignment is not portable. –  MadScientist Mar 19 '13 at 12:32
    
@MadScientist export var=value is POSIX. It isn't portable to Bourne shells, but these are a vanishing breed (just make sure to use /usr/xpg4/bin/sh or /usr/xpg6/bin/sh or ksh and not /bin/sh on older Solaris machines). –  Gilles Mar 19 '13 at 12:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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