Say I have this .env file:

C="3 4 5"

If I run set -x; echo $(cat .env | xargs):

++ cat .env
++ xargs
+ echo A=1 B=2 C=3 4 5
A=1 B=2 C=3 4 5

If I run set -x; export $(cat .env | xargs):

++ cat /tmp/test.env
++ xargs
+ export A=1 B=2 C=3 4 5
+ A=1
+ B=2
+ C=3
bash: export: `4': not a valid identifier
bash: export: `5': not a valid identifier

Then I tried a lot of other tricks to try and keep or add quotes around the C value:

$ set -x; export $(cat /tmp/test.env | xargs printf %q)
+ set -x
++ cat /tmp/test.env
++ xargs printf %q
+ export ''\''A=1'\'''\''B=2'\'''\''C=3' 4 '5'\'''
bash: export: `'A=1''B=2''C=3': not a valid identifier
bash: export: `4': not a valid identifier
bash: export: `5'': not a valid identifier

No matter what I do, the C value is always split on spaces.

Edit: To clarify, a solution based on naively sourcing the .env file(most solutions from How to export variables from a file?) is severely unsafe, if the file contains any string that can be interpreted as command executon. I want my environment files to be interpreted only as key-value data.

  • 5
    What is your goal? Do you need . .env? – Arkadiusz Drabczyk Sep 24 '19 at 14:44
  • you could do something like this: . <(sed -E -n '/^\s*[[:alpha:]_][[:alnum:]_]*=/ s/^/export /p' < .env). The sed command adds "export " to the beginning of lines that look like a valid variable assignment, and drops all other lines from the output. there's bound to be all sorts of horrible failure modes with unexpected input, but it's OK-ish as a quick and dirty hack. – cas Sep 25 '19 at 4:24
  • @ArkadiuszDrabczyk I'd like to avoid sourcing the file, to avoid catastrophic results of evaluating arbitrary bash code. – Charles Langlois Sep 25 '19 at 17:52
  • @cas this could be an ok solution, it seems to work fine. As long as it's strictly better than what I was doing before(which didn't handle spaces in values). – Charles Langlois Sep 25 '19 at 17:57
  • 1
    @CharlesLanglois 1. don't put arbitrary bash code in it, then ;-) 2. you can still be powned in 1e9 ways via environment variables; just think about PATH or LD_PRELOAD; and that's just the beginning 3. Any ad-hoc "parsing" will break sooner or later in dangerous and ridiculous ways; think of eg. a .env file as generated by printf 'key="val\nfoo=bar"\nquux=baz\n'. That's more likely to happen than some evil haxxor trying her hand at you. – mosvy Sep 26 '19 at 19:27

Can you use parset?

parset "`perl -nE '/[^=]+/ && print "$&,"' .env`" echo ::: "`perl -pe 's/[^=]+=//' .env`"

It deals happily with input like:

vv=* ;   & " echo this is a value - not a command

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.