Search code examples
bashdeclare

How to set variables whose name and values are taken from a command's output with `declare` in bash?


I need to declare variables in a bash shell script for which both names and values are taken from another command's output.

For the sake of this question, I will use a temporary file tmp:

$ cat tmp
var1="hello world"
var2="1"

... and use it for my mock command below.

In the end, I need to have the variables $var1 and $var2 set with respectively hello world and 1, with the variable names var1 and var2 taken directly from the input.

Here is what I got so far:

$ cat tmp|while read line; do declare $line; done

I know I don't need to use catbut this is to simulate the fact that the input is taken from the output of an other command and not in a file.

This doesn't work. I get:

bash: declare: `world"': not a valid identifier

and

$ echo $var1; echo $var2


$ 

I don't understand why this doesn't work since I can do this:

declare var1="hello world"

... with expected result. I assumed this would be equivalent, but I'm clearly wrong.

I found this answer as the closest thing to my problem, but not quite since it relies on a file to source. I would like to avoid that. I found other answers that uses eval but I'd prefer to avoid that as well.

Maybe there are subtleties in the use of quotes I don't understand.

If the only way is to use a temporary file and source it that is what I'll do, but I think there must be another way.


Solution

  • A good suggestion when writing a shell script is that always double quoting the variable. Otherwise, it will be affected by the shell word splitting.

    while read line; do
        declare "$line"
    done < <(echo "var1=hello world")
    

    And why echo "var1=hello world" | while read line; do export "$line"; done won't work? Because pipe is a sub-shell, it creates var1 in the sub-shell, it won't impact the current shell. So it can't be set in the current shell.

    As an alternative, use process substitution, you can obtain the output as a temporary file. So it will create the variable in the current shell.