1

Yes, yes, I know you're probably like "Hey, there are hundreds of other people asking this same question", but that's not true; I'm not trying to do something like this:

foo="example1"
bar="example2"
foobar="$foo$bar"

I'm trying to do this:

foo="example1"
$foo="examle2"

But whenever I attempt this, I get an error message that says:

bash: example1=example2: command not found

Any suggestions? Is this even possible?

Anonymous
  • 43
  • 7
  • Yea, there have been a couple of questions of just this within a day or two. I tried to look but didn't find an answer that would deal with all the usual use-cases. So, @Anon, do you have a particular use case in mind? What you're doing might be better done with arrays or associative arrays. – ilkkachu Aug 22 '18 at 19:47
  • @ilkkachu to answer your question, I was using an array that cycled through numbers and then I made a variable for each one that was named whatever variable was selected. The contents of the variable were some text files. So, basically, I was trying to EFFICIENTLY make a textfile updater. – Anonymous Aug 22 '18 at 21:41

3 Answers3

6

Here are some examples:

declare [-g] "${foo}=example2"
declare -n foo='example1'
foo='example2'
eval "${foo}=example2"
mapfile -t "${foo}" <<< 'example2'
printf -v "${foo}" '%s' 'example2'
IFS='' read -r "${foo}" <<< 'example2'
typeset [-g] "${foo}=example2"

As other users said, be careful with eval and with indirect assignments in general.

nxnev
  • 3,634
  • 2
  • 12
  • 28
  • Oh duh! I completely forgot declare and eval! Thanks so much! After testing both, eval worked "letter-for-letter", and declare worked once I removed the [ ]s from the first declare code. – Anonymous Aug 22 '18 at 21:35
  • @AnonymousUser216 Those brackets mean that the `-g` option is, well, optional, so it may or may not be present in the actual command (read the synopsis of some man pages to see more examples of this syntax). If you use `declare var` inside a function, then `var` will be local; but if you use `declare -g var`, then `var` will be global. Although, [according to Stéphane Chazelas](https://unix.stackexchange.com/a/382393/243481), the actual explanation is a bit more complicated. – nxnev Aug 22 '18 at 22:17
  • Trying again, I ran into another problem; I can't assign variable values using your method that have variables in them. Like `eval "${foo}='some text'$bar"` outputs `Command not found`. Help? – Anonymous Aug 22 '18 at 23:32
  • @Anon What's the content of `${bar}`? Remember that `eval` is used in this case to trigger 2 "levels" of execution instead of only one: the first one by the shell (which expands `${foo}`) and the second one by `eval` itself (which runs `example1=example2` as shell code in the current context). So, if `${bar}` holds some value like `word1 word2`, what `eval` sees is `example1='some text'word1 word2`, thus it interprets `word1` as part of the assignment, `word2` as a command and it tries to export the `example1` variable to the `word2` command's environment (which doesn't exist, does it?). – nxnev Aug 23 '18 at 00:16
  • ${bar} is just one word, but don’t worry, I figured out my problem; ${foo}’s value was a number. -silent facepalm- I had forgotten you couldn’t use plain numbers as variables. I added ‘s’ to the front and it worked like a charm. Thank you for your input, though! – Anonymous Aug 23 '18 at 11:13
0

It is possible using eval.

eval $foo="examle2"

Be aware that you should be very sure that the value of $foo can be trusted.

A better alternative is to used indexed arrays, where you don't risk executing arbitrary commands.

RalfFriedl
  • 8,816
  • 6
  • 23
  • 34
0
suffix=bzz
declare -g prefix_$suffix=mystr

...and then...

varname=prefix_$suffix
echo ${!varname}

Shamelessly stolen from here.

Edit: As stated by Stephane this is generally a bad idea and should be avoided. Indexed arrays are a better alternative.

Zachary Brady
  • 4,200
  • 2
  • 17
  • 40
  • 4
    Like for `eval`, _you should be very sure that the value of $suffix can be trusted_. Also note that `declare` has the side effect of restricting the scope of variables when used in a function. Also note that unquoted parameter expansions are subject to split+glob in bash, you should almost never do that. – Stéphane Chazelas Aug 22 '18 at 19:43
  • Note the warning was more in response to the warning about `eval` in other answers. `array[$var]=bar` or any variable used in an arithmetic expression is also a command injection vulnerability (and all of `declare`/`read`/`printf`... can interpret arithmetic expressions) – Stéphane Chazelas Aug 22 '18 at 21:13
  • @ilkkachu, there's [Security Implications of using unsanitized data in Shell Arithmetic evaluation](//unix.stackexchange.com/a/172109) – Stéphane Chazelas Aug 22 '18 at 21:15
  • @StéphaneChazelas, yeah, I meant to check that there wasn't anything _else_ to watch out for with `declare` than the arithmetic expansion. Thanks for the link! – ilkkachu Aug 22 '18 at 21:25
  • Note that in `bash` (contrary to zsh/mksh/yash), `typeset`/`declare -g` doesn't really do what you want here. See for instance `bash -c 'f() { local a=1; g; }; g() { declare -g a=2; echo "$a"; }; f'` and [bash vs zsh: scoping and \`typeset -g\`](//unix.stackexchange.com/q/382380) – Stéphane Chazelas Aug 22 '18 at 21:42
  • @ilkkachu, here, because of the missing quotes, there would be problems with `suffix='foo PATH=/tmp/evil bar'`. There's also things like `b='([0$(uname>&2)]=1)' bash -c 'a=(); declare a=$b'` in addition to `suffix='[0$(uname>&2)]' bash -c 'declare x$suffix=1'` – Stéphane Chazelas Aug 22 '18 at 21:47