fish function to source env variables

Posted on:October 31, 2023

Table of Contents

Open Table of Contents

Introduction

This is a fish shell script to source environment variables from an ‘.env’ file, to hide sensitive information from your shell history or publicly accessible config. Information in ‘.env’ files can vary from API keys, to database passwords, to local development settings, plus a plethora of other possibilities. As a result of the sensitive nature of the information in these files, it is important to keep in mind how they are accessed and used while developing. A common practice to access these variables (especially when their needed across multiple tools), is to read them into the shell environment, and then access them from there. Storing these variables in the shell environment is not always the best option to keep ‘.env’ secrets secure, so be mindful of the shell history if you are storing sensitive information in the shell environment.

Usage

In my case, most of the time I read ‘.env’ files into the shell environment is for my editor, neovim. Neovim offers a feature rich plugin ecosystem, similar to VSCode. Neovim plugins usually need to be configured when they are installed. It might be jarring at first, for new users, to install something and not have it work out of the box. Especially as newer AI tools are becoming more common, having a method of sourcing your editor with API KEYS makes getting ‘shiny’ feautre’s working more secure, faster and easier. can be a daunting task. The method I’ve found most success to provide things of this nature across my entire development environment is by reading them, upon initialization of my fish config. Then all my editor or other tools need to do to access the API KEY is read the value from the shell environment variable. Not only does this help keep my entire system consistent, but it also allows me to keep my editor configuration public, without exposing my API KEYS.

Walkthrough/Setup

Here is how my chapgpt API key is setup to be used across my entire system’s tooling:

  1. Create an API key in chatgpt, (you might have to make a new, if you don’t have access to it).
  2. Store the API key where ever you want. For this walkthrough we’ll be putting it in the file ~/.config/chatgpt/.openai_key.

    This is our ‘.env’ file that will be read when we start our shell. Feel free to use the .env file extension when setting this up on your own machine, but it is not required. For this walkthrough to work properly, you’ll want your ‘.env’ files to be formatted with syntax of the form “KEY=VALUE”, where the key is the name of the variable to source.

# NAME_OF_VARIABLE=VALUE_OF_VARIABLE
OPENAI_API_KEY=xx-XXXXXXXXXXXXXXXXXX
  1. Create a fish function to read the ‘.env’ file into the shell environment. You will want to call this function when the shell is initialized in the ~/.config/fish/config.fish. We will refer to this function as load_env_vars in this walkthrough. Here is how I setup my load_env_vars function:
function load_env_vars -d "Load variables in a .env file"
    set lines (cat $argv | string split -n '\n' | string match -vre '^#')
    for line in $lines
        set arr (string split -n -m 1 = $line)
        if test (count $arr) -ne 2
            continue
        end
        set -gx $arr[1] $arr[2]
    end
end

This function is modified to skip lines that start with a # character. It essentially reads each line of a file into an array, and uses the set -gx command to expose the variable to the shell environment.

  1. Call the load_env_vars function in your ~/.config/fish/config.fish file. Here is how I setup my ~/.config/fish/config.fish file:
# ..................
# other config stuff
# ..................

# Load environment variables from .env file
load_env_vars ~/.config/chatgpt/.openai_key
  1. Restart your shell.
  2. Test that the environment variable is now available in your shell environment. A simple echo $OPENAI_API_KEY should print out your API key.
  3. Use the environment variable in your editor or other tools. In my case, I use the neovim plugin ChatGpt.nvim.

Conclusion

The concept of env variables, is to allow for subprocesses to inherit values their parent process (i.e., the shell) has access too. This makes storing the private environment variables accessible to other tools by only being defined once. Keeping the values in a singular location, makes it harder to accidentally expose the values in a publicly accessible space.

However, as I mentioned in the introduction, env variables can come in a variety of forms. Most programming languages have a way to access these values, and locally scoped project env variables should probably not be exposed to the shell environment. Learning the pattern recognition for what the best approach to handling env variables is something that should feel natural, and not forced.