Cully
Cully

Reputation: 6975

How to pass environment variables from a file to a node command

I have a command I've installed via npm (db-migrate). I want to run it from the command line as part of automating database migration. The config file for the script can reference environment variables. I'm already setting database credentials as environment variables in another file. So rather than set them twice, I told the migration config to use the environment variables. The problem is, how do I get the environment variables from the file before running the migration script? Also, how can I run the migration script directly from the npm bin?

I found a nice general solution to this problem, so I'm posting the question and the answer for at least the benefit of my future self.

Upvotes: 1

Views: 3139

Answers (1)

Cully
Cully

Reputation: 6975

This can be done using a few tools:

  1. Read the environment variables from the file and set them before running the script. To review, it's simple to set an environment variable before running a command:
PORT=3000 node index.js

But we want to read the variables from a file. This can be done using export and xargs:

export $(cat app.env | xargs)
  1. We want to run the script directly from npm's bin. The path to the bin folder can be obtained using npm bin. So we just need to add that to the path before running the command:
PATH=$(npm bin):$PATH
  1. Now put them together:
export $(cat app.env | xargs) && PATH=$(npm bin):$PATH db-migrate up

This reads the environment variables, sets them, adds the npm bin to the path, and then runs the migration script.

By the way, the content of app.env would look something like this:

PORT=3000
DB_NAME=dev
DB_USER=dev_user
DB_PASS=dev_pass

UPDATE:

There are a few caveats with this method. The first is that it will pollute your current shell with the environment variables. In other words, after you run the export...xargs bit, you can run something like echo $DB_PASS and your password will show up. To prevent this, wrap the command in parens:

(export $(cat app.env | xargs) && PATH=$(npm bin):$PATH db-migrate up)

The parens cause the command to be executed in a subshell environment. The environment variables will not bubble up to your current shell.

The second caveat is that this will only work if your environment variables don't have spaces in them. If you want spaces, I found an OK solution based on this gist comment. Create a file named something like load-env.sh:

# loads/exports env variables from a file
# taken from: https://gist.github.com/judy2k/7656bfe3b322d669ef75364a46327836#gistcomment-3239799
function loadEnv() {
    local envFile=$1
    local isComment='^[[:space:]]*#'
    local isBlank='^[[:space:]]*$'
    while IFS= read -r line; do
        [[ $line =~ $isComment ]] && continue
        [[ $line =~ $isBlank ]] && continue
        key=$(echo "$line" | cut -d '=' -f 1)
        value=$(echo "$line" | cut -d '=' -f 2-)
        eval "export ${key}=\"$(echo \${value})\""
    done < "$envFile"
}

Then run your command like this:

(source scripts/load-env.sh && loadEnv app.env && PATH=$(npm bin):$PATH db-migrate up)

Upvotes: 3

Related Questions