11

I am using set -o allexport; source .env; set +o allexport to export all variables from a .env file. Unfortunately, one variable contains ) for which reason it results in a syntax error. Is there a solution to this with the above command? I know it would be possible setting it in parentheses, but the .env is somewhat autogenerated without parentheses.

Dotenv looks like this for example:

username=test
password=*fdas_dfar+)mbn
Peterhack
  • 941
  • 4
  • 15
  • 34
  • Can you please include the `.env` file or an excerpt from it in your question? – oguz ismail Apr 16 '19 at 08:46
  • That is what I want to avoid to do manually. Any command for this available? – Peterhack Apr 16 '19 at 08:52
  • Are you trying to parse the `.env` using external commands and make those variables exported? – Inian Apr 16 '19 at 09:02
  • This can ve done with a `sed` command, but the problem is that the file, which you say it is autogenerated, is wrongly generated. It should quote all the values. You should fix the root, rather than treat the symptoms. – Poshi Apr 16 '19 at 09:03
  • You need to escape your string. Use quotes, or use check this out: https://stackoverflow.com/questions/43676064/convert-strings-to-bash-escaped-form – TheNavigat Apr 16 '19 at 09:14

2 Answers2

13
source .env

source is a shell command and the .env file is parsed as shell file. You need to quote your strings, just as you would in shell.

username=test
password='*fdas_dfar+)mbn'

What is good about it, you can run all shell commands from such file:

username=$(echo test)
password='*fdas_dfar+)mbn'

Or you can write your own parser, ex:

while IFS='=' read -r name value; do
       if [ -z "$value" -o -z "$name" ]; then
           echo "Error - unparsable line!" >&2
           exit 1
       fi

       # add quotes around `'`
       value=$(<<<"$value" sed "s/'/'\''/g")
       
       # set the variable value using bash special builtin
       printf -v "$name" "%s" "$value"

 done <.env
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 1
    You can use `declare -x` and avoid using `eval` – Inian Apr 16 '19 at 09:19
  • how can I call the parser to put quotes around all variables in my .env file? – Peterhack Apr 16 '19 at 11:15
  • You mean you want to edit the `.env` file to put the quotes in it? Which parser do you want to call? The snipped of code I posted is written in bash as a mere starting point for building something more sophisticated. I didn't test the code in any way. – KamilCuk Apr 16 '19 at 11:23
  • I thought this is for put quotes in place in the .env file – Peterhack Apr 16 '19 at 11:25
  • We need to parse the string `password=*fdas_dfar+)mbn` in shell. I use `eval` to re-evaulate the expression. So first I get the string after `=` with `IFs== read`, I am left with `*fdas_dfar+)mbn`. Then if any `'` are inside that string, I substitute `'` with `'\''`. Then I call `eval "$name='$value'"` - so that the variable can be set. This evaulates the `password='*fdas_dfar+)mbn'` line and assigned to the variable `password` the string `'*fdas_dfar+)mbn'`. As the line is parsed by bash, the quotes `'` are removed, because expansion happens. – KamilCuk Apr 16 '19 at 11:29
  • The line of code is to parse the `.env` file and assign proper variable names with proper values as obtained from the `.env` file. The code snipped does not alter the `.env` file. Only after it you can `echo "$password"` and get expected result. – KamilCuk Apr 16 '19 at 11:30
1

If you want to be able to source .env then it needs to be valid shell syntax. That means quoting values that contain shell metachars like ). If that isn't possible because the file also needs to be read by other programs that can't handle the quoting then you will need to read and parse it one line at a time. Do not use eval as suggested in the older answer. The eval command almost always causes more problems than it solves. I prefer this approach over using the IFS trick because IFS is itself inherently dangerous and should always be set to IFS=$'\n' at the top of every script and not subsequently changed:

while read -r line
do
    # Insert appropriate checks for malformed input or comments here.
    key="${line%%=*}"
    val="${line#*=}"
    export "$key"="$val"
done < .env

But if you know the input is well formed and you like living dangerously then this also works fine:

while IFS='=' read -r key val
do
    export "$key"="$val"
done < .env
Kurtis Rader
  • 6,734
  • 13
  • 20
  • I was with you up until the IFS stuff. What's your beef with IFS? – John Kugelman Apr 16 '19 at 19:51
  • There are lots of problems with the POSIX shell standard that shells like bash, ksh, and zsh implement. But one of the worst is `IFS` and the implicit word splitting it causes after variable expansion. It's why you have to double-quote damn near every use of a shell var. – Kurtis Rader Apr 16 '19 at 21:05