47

(I'm talking about the shell Fish, esp. Fish's Fish.)

For Bash/ZSH, I had ~/.profile with some exports, aliases and other stuff.

I don't want to have a separate config for environment variables for Fish, I want to re-use my ~/.profile. How?

In The FAQ, it is stated that I can at least import those via /usr/local/share/fish/tools/import_bash_settings.py, however I don't really like running that for each Fish-instance.

Albert
  • 6,531
  • 11
  • 39
  • 51

10 Answers10

45

You can use bash to parse /etc/profile and ~/.profile, and then start fish.

  1. Create /usr/local/bin/fishlogin with contents

     #!/bin/bash -l
     exec -l fish "$@"
    
  2. Make it executable

     sudo chmod a+rx /usr/local/bin/fishlogin
    
  3. Check that it works by running fishlogin and checking that you end up in a Fish shell. Press Control+D to exit the Fish shell.

  4. Add it to /etc/shells

     echo /usr/local/bin/fishlogin | sudo tee -a /etc/shells
    
  5. Set it as your default shell.

    Under Linux:

     sudo usermod -s /usr/local/bin/fishlogin $USER
    

    Under macOS:

     chsh -s /usr/local/bin/fishlogin $USER
    
Noé Rubinstein
  • 573
  • 1
  • 5
  • 6
  • So elegant! Should be the accepted answer IMO – yonix Mar 22 '17 at 08:11
  • 3
    Just in case anyone is wondering, the mac equivalent of `usermod -s /usr/local/bin/fishlogin $USER` is `chsh -s /usr/local/fishlogin $USER` – gloriphobia May 10 '17 at 09:52
  • 2
    If you get `chsh: /usr/local/bin/fishlogin: non-standard shell` need to add it to `/etc/shells` – electronix384128 Jun 03 '17 at 22:06
  • 2
    To fully imitate launching fish directly, `fish "$@"` should be replaced with `exec -l fish "$@"`. `exec` replaces the bash process with fish, while `-l` causes that `argv[0]` for fish is `-fish`, which signals that this is a login shell. – jhrmnn Feb 12 '18 at 10:28
  • Usually no big deal, but this seems to have the drawback that whenever a subshell is implicitly created, an unnecessary bash instance will also always be launched first. (Note: `~/.profile` is only relevant for login shells.) Still upvoted, though, for its good trade-off between simplicity and hackyness. (I'd personally still rather just tweak my shell config scripts a bit, as I've long given up having complicated ones, in favor of custom shell-independent methods.) – Sz. Sep 14 '18 at 19:49
  • 1
    @Sz. Well, nope. Fish does not support subshells in the first place. And even if it did, it would not do so by executing your login shell, so no Bash would be spawned then. – Noé Rubinstein Oct 03 '18 at 11:12
  • Note that fish reorders and modifies the entries in `$PATH`, which you might find confusing. See [here](https://github.com/fish-shell/fish-shell/issues/927). – Albert Jan 17 '19 at 09:08
  • This just broke my Iterm2 on Mac. Followed the exact steps, now I can't even open iTerms. – Ascendant Nov 28 '20 at 22:16
  • 1
    If following this answer bricks anyone else's iTerm2, here's how to recover: in iTerm2, "Profile" -> "General", make sure the "Command" is set to "Command" and enter "/bin/sh" as the command (or /bin/bash). Cmd+N open a new shell, then `chsh -s /usr/local/bin/fish`. Then undo the beginning steps and change "Command" back to `Login Shell`. – Ascendant Nov 28 '20 at 22:28
  • @AsyncMoksha I'm curious to know how it managed to break. Maybe you could try running `fishlogin` from your current shell and see if it prints any interesting error message? – Noé Rubinstein Nov 30 '20 at 11:27
  • `~/.profile` gets sourced twice, because `--login` (or `-l`) is used twice, once on `bash` and once on `exec`. Remove one of the `-l` flags. – Dominykas Mostauskis Jan 20 '21 at 11:36
  • As far as I can tell, the `exec` builtin does not read `.profile`; all the option does is add a '-' to the start of the first element of argv. – Noé Rubinstein Jan 22 '21 at 21:20
  • If anyone's interested, here's an addition that also gets the `.bashrc`'s aliases: ` #!/bin/bash -i if [ -d "$XDG_RUNTIME_DIR" ]; then alias > "$XDG_RUNTIME_DIR"/.bash_aliases fi exec -l fish --init-command 'source $XDG_RUNTIME_DIR/.bash_aliases' "$@" ` – Timo Kluck Apr 06 '21 at 19:50
  • small typo -> `chsh -s /usr/local/bin/fishlogin $USER` instead of `chsh -s /usr/local/fishlogin $USER` – Mr.O Mar 29 '23 at 10:33
  • @Mr.O thanks, applied – Noé Rubinstein Apr 04 '23 at 08:07
34

For a much cleaner solution, you can use the foreign env plugin:

fenv source ~/.profile
jgillich
  • 1,040
  • 1
  • 12
  • 20
  • 8
    This should be the accepted solution. You could elaborate (install omf) – Jules Sam. Randolph Apr 18 '18 at 20:36
  • 1
    @JulesRandolph installation of Oh My Fish is not required. The foreign_env fish plugin can be installed alone, it doesn't have dependencies. – Dominykas Mostauskis Oct 20 '19 at 16:59
  • This doesn't handle aliases, which make up 80% of my `.bash_profile`, and is therefore useless to me. – Ascendant Nov 28 '20 at 22:37
  • You can add @jgillich solution in your .config/fish/config.fish file ``` if status is-interactive fenv source ~/.profile end ``` That way .profile will always be synced with fish :) – Fer Mena Jun 21 '22 at 20:46
15

My current solution (see here for a maybe more recent version):

egrep "^export " ~/.profile | while read e
    set var (echo $e | sed -E "s/^export ([A-Z_]+)=(.*)\$/\1/")
    set value (echo $e | sed -E "s/^export ([A-Z_]+)=(.*)\$/\2/")

    # remove surrounding quotes if existing
    set value (echo $value | sed -E "s/^\"(.*)\"\$/\1/")

    if test $var = "PATH"
        # replace ":" by spaces. this is how PATH looks for Fish
        set value (echo $value | sed -E "s/:/ /g")

        # use eval because we need to expand the value
        eval set -xg $var $value

        continue
    end

    # evaluate variables. we can use eval because we most likely just used "$var"
    set value (eval echo $value)

    set -xg $var $value
end
Albert
  • 6,531
  • 11
  • 39
  • 51
9

You can use bass, a plugin to execute bash commands in fish.

  1. Install bass.

    $ git clone https://github.com/edc/bass.git
    $ cd bass
    $ make install
    
  2. And then, just put this in your config.fish:

    bass source ~/.profile
    
rsalmei
  • 191
  • 1
  • 2
  • If you're going to use this method, make sure it isn't too slow. I personally started to notice that my shell startup delay was annoyingly long, and tracked it down to bass. – mk12 Sep 05 '19 at 21:01
  • @mk12 probably it isn't bass' fault, it is your `.profile` that has too much going on. – rsalmei Sep 06 '19 at 17:21
  • @rsalmei All I had in there was environment variable and alias definitions, with a few if statements. It causes no noticeable delay in bash. So I think it is bass's fault. On the other hand, I'm much happier with the [fenv plugin](https://github.com/oh-my-fish/plugin-foreign-env). It's written in shell rather than Python and seems much faster for me. – mk12 Sep 07 '19 at 18:05
  • Yeah @mk12, it seems to be nice, but also way more limited, as it only captures environment variables. `bass` on the other hand interprets any bash shell script, and make them run in fish. It certainly will have a bit more overhead, but totally negligible in my experience, but your mileage may vary. – rsalmei Sep 11 '19 at 19:41
6

I tried sourcing .profile on fish startup and it worked like a charm for me.

just do :

echo 'source ~/.profile;clear;' >  ~/.config/fish/config.fish

Restart terminal or iterm2, test an alias from .profile to test.

Note : Won't work with more complex .profile files that use syntax not available in fish - credit @erb

3

Install dash and add this line to your config.fish:

env -i HOME=$HOME dash -l -c 'export -p' | sed -e "/PATH/s/'//g;/PATH/s/:/ /g;s/=/ /;s/^export/set -x/" | source
yegorius
  • 29
  • 2
1

You can't. fish's syntax is too different from Bourne shell (/bin/sh) syntax. This is the same reason you can't use .profile with other non-Bourne-derived shells, such as csh and tcsh.

Spiff
  • 101,729
  • 17
  • 175
  • 229
  • I don't want to fully execute `.profile`. I just want to get all `export`s from there. One easy way would be to `egrep "^export"` which would be good enough already for me. Another, more correct solution would be [this](http://superuser.com/questions/446929/run-any-shell-script-from-fish-and-import-all-exported-env-variables). Also, I e.g. could run this `import_bash_settings.py` script which probably does something similar. So, there are obviously many ways to do this. With my question here, I was wondering how others have solved this. – Albert Jul 11 '12 at 14:18
1

If your distribution uses PAM, you could set your environment variables in your ~/.pam_environment file.

kzh
  • 4,243
  • 7
  • 28
  • 33
1

You can start Fish from Bash. If you do that, Fish will inherit all environment variables (export FOO=bar) from Bash. At this point, Bash will have already read your .profile (or the like).

bash-3.2$ export TEST="test"
bash-3.2$ fish
cmey@MBP ~> echo $TEST
test
cmey
  • 11
  • 1
0

I managed to solve this by adding the following to my ~/.bashrc file:

if [ $SHLVL -lt 2 ]; then 
    fish; 
    exit;
fi

This way one does not have to type exit twice when exiting the fish subshell. Bash subshells inside the fish subshell are not affected.

AsukaMinato
  • 163
  • 1
  • 4
ben
  • 1
  • 1