Search code examples
makefileenvironment-variables

How to load and export variables from an .env file in Makefile?


What is the best way to use a .env in a Makefile, i.e. loading that file and exporting all variables for subshells in make?

It would be great if the proposed solution would work with make only, e.g. not using any third party tools. Also .env files support multiline variables like:

FOO="this\nis\na\nmultiline\nvar"

this is why this solution is probably not adequate.


Solution

  • Make does not offer any way to read a content of the file to some variable. So, I consider it impossible to achieve the result without using external tools. However, if I am wrong, I'd be glad to learn some new trick.

    So, let's assume there are two files, .env, being a technically correct shell file:

    FOO=bar
    
    BAR="notfoo" # comment
       #comment
    MULTILINE="This\nis\nSparta!"
    # comment
    

    and script.sh:

    #!/bin/bash
    echo FOO=${FOO}
    echo BAR=${BAR}
    echo -e ${MULTILINE}
    

    One solution is to include the .env file, then make sure variables are exported:

    include .env
    
    $(eval export $(shell sed -ne 's/ *#.*$$//; /./ s/=.*$$// p' .env))
    
    all:
        ./script.sh
    

    Because of different treatment of quotes by shell and make, you will see the quotes in output.

    You can avoid that by reprocessing the variables by make:

    include .env
    
    VARS:=$(shell sed -ne 's/ *\#.*$$//; /./ s/=.*$$// p' .env )
    $(foreach v,$(VARS),$(eval $(shell echo export $(v)="$($(v))")))
    
    all:
        ./script.sh
    

    but then the multiline variable will become a one-liner.

    Finally, you can generate a temporary file to be processed by bash and source it before any command is run:

    SHELL=bash
    
    all: .env-export
        . .env-export && ./script.sh
    
    .env-export: .env
        sed -ne '/^export / {p;d}; /.*=/ s/^/export / p' .env > .env-export
    

    Oh, new lines got messed in this case in multiline variable. You need to additionally quote them.

    Finally, you can add export to .env using above sed command, and do:

    SHELL=bash
    %: .env-export
        . .env-export && make -f secondary "$@"