15

bash and fish scripts are not compatible, but I would like to have a file that defines some some environment variables to be initialized by both bash and fish.

My proposed solution is defining a ~/.env file that would contain the list of environment variables like so:

PATH="$HOME/bin:$PATH"
FOO="bar"

I could then just source it in bash and make a script that converts it to fish format and sources that in fish.

I was thinking that there may be a better solution than this, so I'm asking for better way of sharing environment variables between bash fish.

Note: I'm using OS X.


Here is an example .env file that I would like both fish and bash to handle using ridiculous-fish's syntax (assume ~/bin and ~/bin2 are empty directories):

setenv _PATH "$PATH"
setenv PATH "$HOME/bin"
setenv PATH "$PATH:$HOME/bin2"
setenv PATH "$PATH:$_PATH"
18

bash has special syntax for setting environment variables, while fish uses a builtin. I would suggest writing your .env file like so:

setenv VAR1 val1
setenv VAR2 val2

and then defining setenv appropriately in the respective shells. In bash (e.g. .bashrc):

function setenv() { export "$1=$2"; }
. ~/.env

In fish (e.g. config.fish):

function setenv; set -gx $argv; end
source ~/.env

Note that PATH will require some special handling, since it's an array in fish but a colon delimited string in bash. If you prefer to write setenv PATH "$HOME/bin:$PATH" in .env, you could write fish's setenv like so:

function setenv
    if [ $argv[1] = PATH ]
        # Replace colons and spaces with newlines
        set -gx PATH (echo $argv[2] | tr ': ' \n)
    else
        set -gx $argv
    end
 end

This will mishandle elements in PATH that contain spaces, colons, or newlines.

The awkwardness in PATH is due to mixing up colon-delimited strings with true arrays. The preferred way to append to PATH in fish is simply set PATH $PATH ~/bin.

| improve this answer | |
  • 1
    Will the PATH fix for fish work with paths with: spaces? newlines? other things to look out for? – Tyilo Dec 28 '14 at 23:28
  • [ is a builtin in both bash and fish, so PATH should not need to be set correctly to use [. The setenv sample should work with all characters in PATH except for colons and newlines. – ridiculous_fish Dec 30 '14 at 0:35
  • Replacing tr with /usr/bin/tr I and using the .env file provided in my question, I get a lot of errors when starting fish. I don't think the PATH handling is correct. – Tyilo Dec 30 '14 at 0:39
  • Oh, right, fish will space-separate it inside quotes. I'll update the comment. – ridiculous_fish Dec 31 '14 at 7:50
  • Yay it works now. I don't think any other shell (except fish?) allows paths with colons in PATH anyway. – Tyilo Dec 31 '14 at 16:38
7

Most Unix systems use PAM. The pam_env module reads a file very much like your .env.

On Linux, pam_env reads a system file /etc/environment and a user file ~/.pam_environment. On OS X (and other *BSD, which likewise use OpenPAM), it appears that pam_env only reads the system file, so you can't set variables per user this way, only for all users.

| improve this answer | |
6

There is (now?) an easier way, per @Zanchey's answer here

Fish Shell: How to set multiple environment variables from a file using export

The digest though is:

Fish:

echo -e "foo=3\nfoobar=4" > .env; export (cat .env); env | grep foo

Bash:

echo -e "foo=3\nfoobar=4" > .env; export $(cat .env | xargs); env | grep foo

with the difference being $ and the use of xargs

| improve this answer | |
  • Much more convinient and without any special syntax. Thank you – Panayotis Jun 27 '18 at 20:18
  • Doesn't work for arrays such as $PATH – JanKanis Jul 8 '19 at 8:49
1

Expanding on @ridiculous_fish's answer, with the following function for bash it also works for arrays that contain spaces, such as $PATH if you have spaces in your paths. However setenv is already defined as a function in the fish standard library nowadays so I changed the name here to shenv

function shenv { 
        var="$1"
        shift
        export "$var=$(printf "%s\n" "$@" | paste -s -d: -)"
}
. ~/.env

Now in your .env file you can specify array components as separate arguments to the setenv command:

shenv PATH /my/path /my/path\ with\ spaces "/my/quoted path" $PATH

For fish @ridiculous_fish's simple implementation will do:

function shenv; set -gx $argv; end
source ~/.env
| improve this answer | |
1

Just create a function in $HOME/.config/fish/functions/env.fish with content:

for f in /etc/profile.d/*.sh
    sh $f
end

shared all vars created in bash in folder /etc/profile.d

for example: /etc/profile.d/golang.sh

#!/bin/sh
export GOPATH=$HOME/gopath
export GOROOT=$HOME/go
export GOBIN=$HOME/gobin

export PATH=$PATH:$GOROOT/bin:$GOBIN

just login on fish or bash, do echo $GOPATH $GOROOT $GOBIN $PATH and see the magic :)

| improve this answer | |
0

If you don't mind fork another process, then:

env $(cat ~/.env) fish

I use this way to share the same .env file with multiple shells in multiple projects. The syntax is easy, and it is quite flexible since you can exit the shell to regain your original environment.

More example:

env $(cat .env) bash

env $(cat .env) zsh

env $(cat .env) sh

One drawback is that it assumes .env only in VAR=value syntax (no comment, newline, or quotes).

I prefer to keep .env as simple as possible by naming variables more sensemaking instead of writing lots of comments and newlines. However, if there are some cases that comments and newlines cannot be avoided, it can still be easily solved by piping output to grep, sed or awk.

Sorry, my solution may not solve the original question because of the syntax of .env, but I did found it useful for sharing the same .env with different shells. Hope it can help anyone of you :)

| improve this answer | |
  • I guess you mean env $(cat ~/.env) fish? – G-Man Says 'Reinstate Monica' May 23 at 6:52
  • @G-ManSays'ReinstateMonica', the command substitution syntax in fish is with (cmd); $(cmd) is the POSIX syntax. – Stéphane Chazelas May 23 at 7:06
  • That assumes ~/.env online contains lines in VAR=value syntax (no comment, no VAR="value", no empty lines...) – Stéphane Chazelas May 23 at 7:07
  • @StéphaneChazelas: OK, but, since the answer is giving a command to start a fish, I assumed that it was meant to be run from bash. Perhaps the answer is what Jian meant, but, if he meant “start a fish process, and then use this command to start another fish process”, I believe he should clarify. – G-Man Says 'Reinstate Monica' May 23 at 7:14
  • @StéphaneChazelas: And your second comment would be clearer if you said “values cannot contain space character(s), whether quoted/escaped or not.”   And I don’t see a problem with empty lines. – G-Man Says 'Reinstate Monica' May 23 at 7:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.