mokacoding

unit and acceptance testing, automation, productivity

Injecting environment variables from a file with xargs

TL;DR

You can use

env $(cat .env | grep -v "#" | xargs) your_command_expecting_env_vars

to run your_command_expecting_env_vars providing it the content of .env like you would do when running FOO=1 BAR=2 your_command_expecting_env_vars.

TS;WR

Many command lines tool can read, or even expect, values set in environment variables.

It is a common practice to place environment variables contextual to a project in a .env file in the project root, and there are tools like dotenv that allow you to load those variables into your application.

Sometimes thought you just need to set a handful of values and cannot be bothered typing FOO=1 BAR=2 BAZ=3 bundle exec foobarbaz. Or maybe your cli tool expects a token that you don't want to store in the repo, but at the same time cannot type every time.

In such cases it might be useful to place those environment variables in a .env file, but how to load them?

This is one possible way:

env $(cat .env | grep -v "#" | xargs) your_command_expecting_env_var

Let's disassemble this long command, shall we?

$(...) will be evaluate it's content before the command is interpreted and run, and replaced with the result, so that what actually is run will be env result your_command_expecting_env_var.

cat .env will put the content of the .env file into the standard output. This would normally be the screen, but in this case there is a pipe operator.

grep -v "#" is an inverted match grep. By default grep selects lines containing the given pattern, the string # in our case, from its standard input. With the -v, or --invert-match it will select the lines not matching the given string.

So cat .env | grep -v "#" results in the content of .env apart from comment lines sent to the standard output, where xargs is there to wait for it. xargs builds an argument list out of its standard input.

This argument list is fed to env. The synopsis of this command is:

env [-i] [name=value ...] [utility [argument ...]]

What env does is executing utility after modifying the environment as specified by the name=value ... list. And that is exactly the end result that we are looking for 😎

A nice thing to notice is that env doesn't export the name=value inputs, so that the environment is not polluted.

Hope you found this article useful, this is the SO answer that inspired and helped me with this approach.

If you need help get in touch with me on Twitter @mokagio, or leave a comment below. And don't forget to hit the share button 😉.

Happy coding, and leave the codebase better than you found it.

Want more of these posts?

Subscribe to receive new posts in your inbox.