Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to set $PATH persistently? #527

Closed
dag opened this Issue Jan 18, 2013 · 42 comments

Comments

Projects
None yet
@dag
Copy link
Contributor

dag commented Jan 18, 2013

I try set -U PATH ~/.cabal/bin $PATH which sets it in the shell I type it in, but not any new shells I launch and it's gone if I restart the first shell as well.

Using git HEAD on Fedora 18.

@siteshwar

This comment has been minimized.

Copy link
Member

siteshwar commented Jan 18, 2013

I think it's because PATH variable is handled specially in Fish. So you can't make it universal etc. I am not aware about the reasons behind it. May be @ridiculousfish or @JanKanis would like to say few words about it.

On Linux I set PATH in ~/.config/fish/config.fish this way :

set -gx PATH /opt/qt/Tools/QtCreator/bin /opt/qt/5.0.0/gcc_64/bin $PATH
@JanKanis

This comment has been minimized.

Copy link
Member

JanKanis commented Jan 18, 2013

PATH is normally a global variable, created when fish starts from the environment variable in its environment. If you do set -U PATH <something> that creates a universal variable PATH, but the universal one is shadowed by the global one, so you won't see it. It could work if you do set -eg PATH (delete the global PATH), and you also need to specify the -x flag when you create the universal PATH (set -Ux PATH <something>). But if you execute e.g. a new X terminal, the fish in it again finds a PATH in its environment so it again creates a global PATH. I would recommend you set your path by doing

set PATH <mydir> $PATH

in your config.fish, so it gets executed every time fish starts. That just modifies the existing global PATH.

@dag

This comment has been minimized.

Copy link
Contributor Author

dag commented Jan 18, 2013

Ah. I was just wondering if there was a neatly interactive/"live" way to do it.

@JanKanis

This comment has been minimized.

Copy link
Member

JanKanis commented Jan 18, 2013

config.fish lives (by default) in ~/.config/fish/config.fish, and it is
mentioned in the user docs. (But maybe it should be made more clear).
There's also vared for interactive editing of variables (however it only
works on one array element at the time).

On 18 January 2013 21:07, Dag Odenhall notifications@github.com wrote:

Ah. I was just wondering if there was a neatly interactive/"live" way to
do it. config.fish doesn't seem to be documented either so I was
wondering if there even was such a file.


Reply to this email directly or view it on GitHubhttps://github.com//issues/527#issuecomment-12438806.

@dag

This comment has been minimized.

Copy link
Contributor Author

dag commented Jan 18, 2013

Yea I was looking in the wrong page. I edited that comment but github sent the mail notification faster.

@ridiculousfish

This comment has been minimized.

Copy link
Member

ridiculousfish commented Jan 27, 2013

When fish starts, it modifies PATH to include its bin directory. We really want to be able to tell users that they can permanently modify PATH via set -U. So we sort of want a two-level PATH - what fish adds local to the current session, and also what the user specifies, universally across all sessions.

@ridiculousfish

This comment has been minimized.

Copy link
Member

ridiculousfish commented Feb 8, 2013

Since setting $PATH is very common, I think it's important to have a story for fish 2.0 that doesn't require the user to edit config.fish. However, simply making it universal is dangerous, because fish is relocatable. If fish is run from /usr/local/bin and also from ~/github/fish/, we want to allow these instances to have distinct PATHs because they have distinct $__fish_bin_dirs. On the other hand, we also want to allow the user to specify one of those bin directories directly.

Here's what I'm thinking:

  1. A variable $fish_user_paths which will be universal. We encourage the user to set it.

  2. A variable $fish_default_paths which will be global (per-process), and that will be set in share/config.fish. It will have at a minimum $__fish_bin_dir, which is fish's bin directory.

  3. $PATH will be global and exported.

  4. There will be an event handler that watches for changes to $fish_user_paths, and updates $PATH like so:

    function __fish_update_path --on-event path-var-changed
    set -gx PATH $fish_user_paths $fish_default_paths
    end

perhaps with some uniqueing to avoid duplicates.

With this design, then:

  1. Setting PATH in config.fish will continue to work, unless something changes $fish_user_paths, which fish will never do on its own.
  2. To add a path to PATH universally, set $fish_user_paths.

I'm not super-happy with this because it requires three variables - it would be nice if there were an approach that only required $PATH. Thoughts?

@JanKanis

This comment has been minimized.

Copy link
Member

JanKanis commented Feb 9, 2013

Another option that came to mind (though I'm not necessarily advocating for
it, just listing it as another option): Drop the restriction that $PATH can
only contain valid directories, then make it universal. That way a user
could just add all the directories that are possibly needed. Hmm, on second
thought, fish also needs the option of adding its own bindir to PATH,
without clobbering up user settings, so that brings my thinking to a
solution containing a user-settable path and a fish-settable path, i.o.w.
something like you propose.

Another design choice could be to rename $fish_user_paths to the universal
$PATH, and shadow it by a global $PATH, that would save a variable but it's
probably more confusing for users, so not really worth it.

On 8 February 2013 23:17, ridiculousfish notifications@github.com wrote:

Since setting $PATH is very common, I think it's important to have a
story for fish 2.0 that doesn't require the user to edit config.fish.
However, simply making it universal is dangerous, because fish is
relocatable. If fish is run from /usr/local/bin and also from
~/github/fish/, we want to allow these instances to have distinct PATHs
because they have distinct $__fish_bin_dirs. On the other hand, we also
want to allow the user to specify one of those bin directories directly.

Here's what I'm thinking:

  1. A variable $fish_user_paths which will be universal. We encourage
    the user to set it.

  2. A variable $fish_default_paths which will be global (per-process),
    and that will be set in share/config.fish. It will have at a minimum
    $__fish_bin_dir, which is fish's bin directory.

  3. $PATH will be global and exported.
    4.

    There will be an event handler that watches for changes to
    $fish_user_paths, and updates $PATH like so:

    function __fish_update_path --on-event path-var-changed
    set -gx PATH $fish_user_paths $fish_default_paths
    end

perhaps with some uniqueing to avoid duplicates.

With this design, then:

  1. Setting PATH in config.fish will continue to work, unless something
    changes $fish_user_paths, which fish will never do on its own.
  2. To add a path to PATH universally, set $fish_user_paths.

I'm not super-happy with this because it requires three variables - it
would be nice if there were an approach that only required $PATH. Thoughts?


Reply to this email directly or view it on GitHubhttps://github.com//issues/527#issuecomment-13315434..

@ridiculousfish

This comment has been minimized.

Copy link
Member

ridiculousfish commented Feb 10, 2013

Having a universal PATH that just accumulates seems harmless. Another thought I had was to try to fix fish so it doesn't depend on PATH to find its own binaries. Then it wouldn't need to modify PATH at all.

@ridiculousfish

This comment has been minimized.

Copy link
Member

ridiculousfish commented Feb 20, 2013

It strikes me that PATH ought never to be a universal variable, because it must be inherited from the environment. That is, if someone sets PATH in bash and then invokes fish, fish ought to respect that, and not overwrite it a universal value.

Here's what I ended up doing:

  1. fish no longer modifies PATH for its own purposes. It knows how to find its own binaries (like fish_indent) without PATH.
  2. Introduced the variable $fish_user_paths. When you modify fish_user_paths, a little function (defined in share/config.fish) runs which performs the same modifications to PATH. fish_user_paths is intended to be universal.

So this is similar to my proposal, except we don't need fish_default_paths. And I think the separation between "here's stuff from the environment" and "here's stuff to add to it" is good. I also like that it required no changes to fish proper, just to config.fish.

So now to append to PATH persistently, append to fish_user_paths, e.g. set -U fish_user_paths ~/bin . I added a note in the documentation too.

To git@github.com:fish-shell/fish-shell.git
2f43584..d3e9183 master -> master

@saulshanabrook

This comment has been minimized.

Copy link

saulshanabrook commented Oct 24, 2013

Is there a reason we don't prepend to PATH instead of append? That way use set paths will take precedence, which is my desired use case, at least for Homebrew (/usr/local/bin).

@ridiculousfish

This comment has been minimized.

Copy link
Member

ridiculousfish commented Oct 25, 2013

In fish 2.1, we do prepend.

@xfix

This comment has been minimized.

Copy link
Member

xfix commented Oct 25, 2013

@saulshanabrook: Already fixed with issue #888.

Anyway, I think that universal PATH could be possible, if the PATH would be considered to be just a hint. All directories in PATH would be added to PATH received from environment, unless they already exist, so unless you would really try, you wouldn't break fish.

@sjatkins

This comment has been minimized.

Copy link

sjatkins commented Nov 1, 2013

Not having PATH simply changeable by a normal user action is a major issue and contrary to the beautiful simplicity of fish relative to other shells. Please fix this. It is really a royal pain. I want to set the path and have it work from then on at least in current session if not universally. Do you know how much of a surprise it is that
set -U PATH $PATH my_path
results in an unchanged $PATH? It is ridiculous.

@zanchey

This comment has been minimized.

Copy link
Member

zanchey commented Nov 1, 2013

Part of the surprise is due to the fact that you can set universal variables and have global variables override them without warning; perhaps at least in interactive mode we should warn when setting a global or universal variable that has a more specifically-scoped variable with the same name set. This has bitten other variables as well, such as $TERM in #806.

@terlar

This comment has been minimized.

Copy link
Contributor

terlar commented Nov 1, 2013

EDIT: I just realized this is mentioned above.

If you just want to set the path for the current session, omit the scope and just do set PATH $PATH my_path. This will use whatever scope is used by this session, in this case global.

If you want to persistently add paths you do this through manipulating fish_user_paths. This is a universal variable, set fish_user_paths $fish_user_paths my_path.

@daenney

This comment has been minimized.

Copy link

daenney commented Nov 3, 2013

If I set something in $fish_user_paths like /usr/local/bin which is also added through an entry in /etc/paths on OS X /usr/local/bin isn't advanced on $PATH, it stays at the 'back'.

@ridiculousfish stated in fish 2.1 values from $fish_user_paths are prepended to $PATH but it looks like that only happens if the path being added is 'new', if it already exists it stays put.

This is causing slightly whacky behaviour on my system since which pip now returns /usr/local/bin/pip from my homebrew python install but which python return /usr/bin/python, the OS X python install.

The brew plugin in bpinto/oh-my-fish fixes it though but still.

@dideler

This comment has been minimized.

Copy link
Contributor

dideler commented Jan 14, 2014

Correction

The handler for fish_user_paths doesn't set $fish_user_paths as universal.
The correct way to persistently add a path to your $PATH (AFAIK) would be

set --universal fish_user_paths $fish_user_paths ~/path/name

Original post

After some reading and playing around with trying to figure out the "best" way to persistently add a path to your $PATH, I think @terlar's suggestion is best. That is

set fish_user_paths $fish_user_paths my_path
  • Specifying the -U/--universal flag like in set -U fish_user_paths $fish_user_paths my_path seems to be redundant.

  • Leaving out the $fish_user_paths as seen in some places, seems to overwrite your most recent path if you run this command twice with different paths:

    set -U fish_user_paths path1
    set -U fish_user_paths path2
  • Setting the $PATH on every shell instance (e.g. by putting set PATH $PATH my_path in your config.fish) is less efficient than a universal variable that you set once.

@denji

This comment has been minimized.

Copy link

denji commented Mar 6, 2014

# NOTE: There is probably a sexier nicer way to do this, but until I figure that out I am manually unsetting here.
# Unsets PATH
set -g -x PATH

# This allows us to use Homebrew versions of things (like git) rather than the pre-installed or XCode installed versions.
# See http://blog.grayghostvisuals.com/git/how-to-keep-git-updated/ for reference.
set -g -x PATH $PATH /usr/local/bin

# Sets necessary PATH defaults
set -g -x PATH $PATH /usr/bin /bin /usr/sbin /sbin
@yannickoo

This comment has been minimized.

Copy link

yannickoo commented Dec 9, 2014

Thank you @dideler, following works fine for adding rvm again:

set --universal fish_user_paths $fish_user_paths ~/.rvm/bin

@Dorian

This comment has been minimized.

Copy link

Dorian commented Jan 13, 2016

@yannickoo 👍 set --universal fish_user_paths $fish_user_paths ~/.rvm/bin worked for me

@timthelion

This comment has been minimized.

Copy link

timthelion commented Mar 13, 2016

Well, I think that those utilities are provided in the plan9port in order to allow historic rc shell(plan9's own shell) scripts to work. Obviously, fish will never be (doesn't even want to be) compatible with those old plan9 shell scripts. So there is no reason to have access to those old utilities. However, that doesn't mean that a person wouldn't ever want to use plan9 utilities that don't exist in GNU posix or BSD... So for plan9port, in my opinion, it is best to append to the path and not prepend it. However, I understand that it would be unreasonable to change the behavior of $fish_user_paths just for plan9port ;). So my comment was more of a mater of interest. I ended up putting the appropriate commands in ~/.config/fish/config.fish.

kc1212 added a commit to kc1212/dotfiles that referenced this issue Sep 29, 2016

hasit added a commit to hasit/yarn that referenced this issue Oct 11, 2016

Use a more modern way of setting $PATH in fish
Set `~/.yarn/bin` in `$fish_user_paths` instead of setting it in `~/.config/fish/config.fish` file.

See [suggestion from fish documentation](fish-shell/fish-shell#527 (comment)) for more reference.

cpojer added a commit to yarnpkg/yarn that referenced this issue Oct 12, 2016

Handle installation for 'fish' shell (#690)
* Handle installation for 'fish' shell

'fish' is a popular shell. This commit adds support for proper detection and installation of yarn in 'fish' shell. If the detected shell is 'fish', add path to ~/.yarn/bin in $HOME/.config/fish/config.fish file.

* Use a more modern way of setting $PATH in fish

Set `~/.yarn/bin` in `$fish_user_paths` instead of setting it in `~/.config/fish/config.fish` file.

See [suggestion from fish documentation](fish-shell/fish-shell#527 (comment)) for more reference.

* Run command to set $fish_user_paths instead of evaluating a string.
@nhooyr

This comment has been minimized.

Copy link
Contributor

nhooyr commented Oct 13, 2016

How can you set fish_user_paths in shared dotfiles? Should I be using only $PATH instead?

@faho

This comment has been minimized.

Copy link
Member

faho commented Oct 14, 2016

@nhooyr: You could use $PATH, or you could add

if not set -q fish_user_paths[1]
    set -U fish_user_paths SOMEVAL
end

That being said, we should probably just remove the host part from the variable store. This is at least the third time in the last week this has come up.

@nhooyr

This comment has been minimized.

Copy link
Contributor

nhooyr commented Oct 14, 2016

@faho is there any advantage to using fish_user_paths for me?

@faho

This comment has been minimized.

Copy link
Member

faho commented Oct 14, 2016

@nhooyr: The nice thing about universal variables is that you can set-and-forget. Need another component in $PATH? Run set fish_user_paths $fish_user_paths /some/path once and you're done. It's even synced to every currently running shell on that machine.

Of course since the store is currently not something you can just keep in git and use across machines it loses a bit of its utility, and I set all of them via a config file because of that.

@nhooyr

This comment has been minimized.

Copy link
Contributor

nhooyr commented Oct 14, 2016

@faho So no advantage for me right now because I need to sync across machines. Might as well use $PATH then. Thanks!

@heyakyra

This comment has been minimized.

Copy link

heyakyra commented Sep 19, 2017

I came here trying to figure out how to get Cabal for Haskell set up with fish.

What is the difference between:

set --universal fish_user_paths $fish_user_paths ~/.cabal/bin

and

set fish_user_paths $fish_user_paths ~/.cabal/bin

@mqudsi

This comment has been minimized.

Copy link
Contributor

mqudsi commented Sep 19, 2017

It's the difference between set and set --universal, documented here: https://fishshell.com/docs/current/commands.html#set

-U or --universal causes the specified shell variable to be given a universal scope. If this option is supplied, the variable will be shared between all the current users fish instances on the current computer, and will be preserved across restarts of the shell.

In this case, since fish_user_paths is already defined as a universal variable (and is not explicitly shadowed in another scope), set fish_user_path ... will be as-if the same scope as the existing variable were applied to them (so an implicit --universal).

@faho

This comment has been minimized.

Copy link
Member

faho commented Sep 19, 2017

@thekyriarchy: You'll want to see the fish documentation on "Shell variables" - specifically the "Variable scope" section (which is repeated in the set documentation).

In short: The former explicitly sets the universal variable. If that doesn't exist, it creates it. If it does, it modifies it - even if a variable of the same name exists in a different scope.

The latter will either modify the existing variable in the lowest scope (which could be local, global or universal - in that order), or it could create a function-scoped variable.

It's good form to explicitly specify the scope, so I'd recommend the former.

@heyakyra

This comment has been minimized.

Copy link

heyakyra commented Sep 20, 2017

I tried both with and without --universal but either way it seems to not be preserved after reboots.

@faho

This comment has been minimized.

Copy link
Member

faho commented Sep 20, 2017

@thekyriarchy: What is your setup? OS? fish version? What are the values of $HOME and $XDG_CONFIG_HOME?

If you echo $fish_user_paths right after starting fish, what does that print?

@krader1961

This comment has been minimized.

Copy link
Contributor

krader1961 commented Sep 20, 2017

@thekyriarchy, What version of fish are you running? What do the following commands output:

echo $HOME
ls -ld $HOME/.config/fish
ls -l $HOME/.config/fish
echo $XDG_CONFIG_HOME
ls -ld $XDG_CONFIG_HOME/.config/fish
ls -l $XDG_CONFIG_HOME/.config/fish
set -U | grep fish_user_paths
set -g | grep fish_user_paths
set -l | grep fish_user_paths
set -U | grep PATH
set -g | grep PATH
set -l | grep PATH

jloh added a commit to jloh/fishtank that referenced this issue Dec 5, 2017

matthiasr added a commit to matthiasr/profile that referenced this issue Apr 6, 2018

Use fish_user_paths instead of manipulating PATH
fish-shell/fish-shell#527

handles the case nicely where one of them is already in PATH

Signed-off-by: Matthias Rampke <matthias@rampke.de>
@Mc128k

This comment has been minimized.

Copy link

Mc128k commented Aug 12, 2018

Alternative solution, thanks to Google Cloud SDK:

Place the file path.bash.inc in the folder you want to add, e.g. the ~/go folder:

script_link="$( command readlink "$BASH_SOURCE" )" || script_link="$BASH_SOURCE"
apparent_sdk_dir="${script_link%/*}"
if [ "$apparent_sdk_dir" == "$script_link" ]; then
  apparent_sdk_dir=.
fi
sdk_dir="$( command cd -P "$apparent_sdk_dir" > /dev/null && command pwd -P )"
bin_path="$sdk_dir/bin"
export PATH=$bin_path:$PATH

Note that this appends the /bin folder, it's actually a good practice to put execs inside a folder named bin.

In fish config add the line:

bass source '/Users/yourUser/go/path.bash.inc'

This is nice, works everywhere

@NikhilVerma

This comment has been minimized.

Copy link

NikhilVerma commented Oct 3, 2018

Just a warning to everyone here, I was bitten by this issue so I want to share

set fish_user_paths $fish_user_paths /some/path

If you do this your fish config cache will grow every single time you open your terminal, in my case it became several megabytes and the fish shell took ages to open.

The files are located in ~/.config/fish/fishd.xxx have a look at yours.

In my case the solution was to do

set fish_user_paths $PATH /some/path

@mqudsi

This comment has been minimized.

Copy link
Contributor

mqudsi commented Oct 24, 2018

@NikhilVerma it's easier to just shadow fish_user_paths instead, like set -g fish_user_paths foo $fish_user_paths, which does not result in recursive modifications that balloon out of hand.

zx1986 added a commit to zx1986/xProfile that referenced this issue Nov 23, 2018

@sztadii

This comment has been minimized.

Copy link

sztadii commented Mar 14, 2019

SET fish_user_paths:/Users/sztadhaus/Library/Android/sdk

worked for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.