Read env variable with unescaped characters from file on ubuntu with bash

Viewed 92

How to read environmental variable in bash that contains spaces and possibly other characters that need to be escaped?

I have a file server.env

PUBLIC_KEY=ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user@alans-MacBook-Pro.local

I am trying to read this file into bash script as an environmental variable:

export $(cat server.env | xargs)

I am getting an error:

-bash: export: `user@alans-MacBook-Pro.local': not a valid identifier

OK, trying to quote the value in server.env:

PUBLIC_KEY='ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user@alans-MacBook-Pro.local'
  • the same error

Double quote:

PUBLIC_KEY="ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user@alans-MacBook-Pro.local"
  • also errors

What am I missing here?

3 Answers

Bash provides parameter expansion with substring removal that will allow you to separate the NAME=value pairs read from the server.env file and then export the NAME=value pairs.

A simple read loop is all you need:

#!/bin/bash

while read -r line; do              ## read each line of server.env
    val="${line#*=}"                ## trim to 1st =, save in val
    export ${line%=$val}="$val"     ## remove =$val leaving name, export val with name
done < server.env

printf "%s\n" "$PUBLIC_KEY"         ## confirm

Example Use/Output

$ bash test.sh
ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user@alans-MacBook-Pro.local

Where the basic Parameter Expansions are:

${var#pattern}      Strip shortest match of pattern from front of $var
${var##pattern}     Strip longest match of pattern from front of $var
${var%pattern}      Strip shortest match of pattern from back of $var
${var%%pattern}     Strip longest match of pattern from back of $var

(note: pattern can contain normal shell globs like '*' and '?')

There are literally dozens of useful parameter expansions you can use for string manipulations. Just check man bash under the "Parameter Expansion" heading.

PARTIAL ANSWER (does not export, so the variable is not available in subsequent runs of bash, only in the current session):

source server.env

The problem here is that field splitting still occurs on the whitespace.

You should do this:

export "$(cat server.env)"

(i.e. add double quotes).

For multiple variables, loop over the lines:

while read -r line
do
    export "$line"
done < server.env

If this is in a script called export.sh, then you will also want to source it for the variables to be set in the current process:

source export.sh
Related