26

If I want to inherit environment variables to child processes, i do something like:

export MYVAR=tork

Assume I have a a file site.conf containing assignments of values (that can contain spaces) to variables:

EMAIL="dev@example.com"
FULLNAME="Master Yedi"
FOO=bar

Now I would like to process this file whenever I open a new shell (e.g. with some code in ~/.bashrc or ~/.profile), so that any processes started from within that newly opened shell will inherit the assignments via environmental variables.

The obvious solution would be to prefix each line in site.conf with an export and just source the file. However I cannot do this since the file is also read (directly) by some other applications, so the format is fixed.

I tried something like

cat site.conf | while read assignment
do
  export "${assignment}"
done

But this doesn't work, for various reasons (the most important being that export is executed in a subshell, so the variable will never be exported to the children of the calling shell).

Is there a way to programmatically export unknown variables in bash?

codeforester
  • 39,467
  • 16
  • 112
  • 140
umläute
  • 28,885
  • 9
  • 68
  • 122
  • Related: [A variable modified inside a while loop is not remembered](https://stackoverflow.com/q/16854280/6862601). – codeforester Sep 18 '19 at 20:01

1 Answers1

50

Run set -a before sourcing the file. This marks all new and modified variables that follow for export automatically.

set -a
source site.conf
set +a  # Require export again, if desired.

The problem you observed is that the pipe executes the export in a subshell. You can avoid that simply by using input redirection instead of a pipe.

while read assignment; do
  export "$assignment"
done < site.conf

This won't work, however, if (unlikely though it is) you have multiple assignments on one line, such as

EMAIL="dev@example.com" FULLNAME="Master Yedi" 
chepner
  • 497,756
  • 71
  • 530
  • 681
  • Your last paragraph is incorrect, `export` will still work with multiple affectations in a single line. – jlliagre Sep 24 '15 at 16:08
  • `export` does, but the need to quote `$assignment` breaks it. A line like `foo=1 bar=2` results in `export "foo=1 bar=2"`, which sets `foo` to `1 bar =2`. Writing `export $assignment` wouldn't work if any of the values were quoted: `assignment='foo="hello world"'` results in an attempt to define an environment variable named `world"`, and `assignment='foo="hello"'` results in the value of `foo` being `"hello"`, not `hello`. – chepner Sep 24 '15 at 16:10
  • Using an array and `export "${assignment[@]}"` would work, assuming you could parse a series of assignments into an array; that is beyond `read`'s capabilities in general. – chepner Sep 24 '15 at 16:15
  • Indeed, I missed the space issue. Leaving the variable unquoted and using `eval` would be simpler and allow the multiple assignments case. – jlliagre Sep 24 '15 at 16:29
  • `eval` introduces even worse issues. – chepner Sep 24 '15 at 16:46
  • Just curious is there any functional difference between `export $(xargs – voutasaurus Mar 23 '18 at 03:47
  • 1
    The second is preferable by far; the first assumes that word-splitting and pathname expansion won't make any changes to the output of `xargs` before `export` sees them. – chepner Mar 23 '18 at 12:05