set -Ua fish_user_paths /path/to/add
contains /path/to/add $fish_user_paths; or set -Ua fish_user_paths /path/to/add
Top comment hijacked by @ridiculousfish to help people landing here from search engines. Original comment follows:
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.
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
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.
Ah. I was just wondering if there was a neatly interactive/"live" way to do it.
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 [email protected] 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/fish-shell/fish-shell/issues/527#issuecomment-12438806.
Yea I was looking in the wrong page. I edited that comment but github sent the mail notification faster.
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.
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:
$fish_user_paths which will be universal. We encourage the user to set it.$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.$PATH will be global and exported.$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:
$fish_user_paths, which fish will never do on its own.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?
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 [email protected] 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:
- A variable $fish_user_paths which will be universal. We encourage
the user to set it.- 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.- $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
endperhaps with some uniqueing to avoid duplicates.
With this design, then:
- Setting PATH in config.fish will continue to work, unless something
changes $fish_user_paths, which fish will never do on its own.- 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/fish-shell/fish-shell/issues/527#issuecomment-13315434..
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.
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:
$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 [email protected]:fish-shell/fish-shell.git
2f43584..d3e9183 master -> master
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).
In fish 2.1, we do prepend.
@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.
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.
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.
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.
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.
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
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
-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
$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.# 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
Thank you @dideler, following works fine for adding rvm again:
set --universal fish_user_paths $fish_user_paths ~/.rvm/bin
Hm, well, I just did set --universal fish_user_paths $fish_user_paths ~/plan9/bin and ended up with a broken system :P so prepending $PATH isn't always the right thingâ„¢.
@timthelion: In what way broken? Did you add it interactively or via config.fish (or similar)? (I'm asking because appending unconditionally to universal variables will cause them to blow up)
Or does your plan9 stuff just shadow something? Like e.g. it has an incompatible "grep"?
Yes, it shadows almost everything, but it has extra commands as well, like venti and vac...
[00:06:26] timothy@timothy-debian-hp /home/timothy/plan9/bin (0)
> ls
"* codereview.py* gif* ndbmkhosts* rsagen* tr*
""* colors* grap* ndbquery* sam* tr2post*
9* comm* graph* netfileget* samsave* tref*
9660srv* core* grep* netfilelib.rc samterm* troff*
9a* crop* gunzip* netfileput* scat* troff2html*
9ar* date* gview* Netfiles* secstore* troff2png*
9c* db* gzip* netfilestat* secstored* tweak*
9fs* dc* hget* netkey* secuser* u*
9import* dd* hist* news* sed* unicode*
9l* delatex* hoc* nobs* seq* uniq*
9p* deroff* htmlfmt* nroff* sftpcache* units*
9pfuse* devdraw* htmlroff* osxvers* sha1sum* unmount*
9pserve* dial* ico* p* sig* unutf*
9.rc* dict* iconv* page* slay* unvac*
9term* diff* idiff* passwd* sleep* unzip*
acid* disk/ img* pbd* sort* upas/
acidtypes* disknfs* import* pemdecode* spell* u.rc*
acme* dns* ipso* pemencode* split* usage*
acmeevent* dnsdebug* join* pic* sprog* vac*
adict* dnsquery* jpg* plot* src* vacfs*
aescbc* dnstcp* kill* plumb* srv* vbackup*
ascii* doctype* label* plumber* ssam* vcat*
asn12dsa* dsa2pub* lc* png* ssh-agent* venti/
asn12rsa* dsa2ssh* lex* ppm* stack* vmount*
astro* dsagen* listen1* pr* start* vmount0*
auxclog* dsasign* look* primes* stats* vnfs*
auxstats* du* lookman* proof* statusbar* vwhois*
awd* dump9660* lpbin/ ps* stop* wc*
awk* E* ls* psdownload* strings* web*
B* echo* Mail* psfonts* sum* win*
basename* ed* man* psu* tail* wintext*
bc* eqn* mapd* psv* tar* wmail*
bmp* factor* mc* ramfs* tbl* xd*
bundle* factotum* md5sum* rc* tcolors* xshove*
bunzip2* file* mk* read* tcs* yacc*
bzip2* fmt* mk9660* readcons* tee* yesterday*
cal* fortune* mkdir* resample* test* yuv*
calendar* fossil/ mklatinkbd* rio* time* zerotrunc*
cat* freq* mount* rm* togif* zip*
cb* fs/ mtime* rsa2csr* toico*
cleanname* fsize* namespace* rsa2pub* topng*
cmapcube* g* ndbipquery* rsa2ssh* toppm*
cmp* Getdir* ndbmkdb* rsa2x509* touch*
codereview* getflags* ndbmkhash* rsafill* tpic*
Now do you undestand what I mean by broken ;)
Now do you undestand what I mean by broken ;)
Yes. And in this case prepending to PATH is _definitely_ the wrong thing (like you said), but I'm not sure appending is much better. Of course it'd be nice to know what breaks, maybe we can fix it - which behavior do we rely on that the plan9 tools don't implement? I assume when they call something "mkdir" it makes directories, but it doesn't necessarily have a "-p" option.
Though my copy of the plan9port intro man page explicitly recommends against prepending to $PATH.
It does support mkdir -p, which is the most common result when grepping the source tree for system(, rm -Rf is the other one and that would fail as plan9's rm only recurses if given -r. Both are only used in the tests though so may not matter. Of course the brokenness in the library of .fish shell-scripts may be intense.
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.
How can you set fish_user_paths in shared dotfiles? Should I be using only $PATH instead?
@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.
@faho is there any advantage to using fish_user_paths for me?
@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.
@faho So no advantage for me right now because I need to sync across machines. Might as well use $PATH then. Thanks!
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
It's the difference between set and set --universal, documented here: https://fishshell.com/docs/current/commands.html#set
-Uor--universalcauses 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).
@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.
I tried both with and without --universal but either way it seems to not be preserved after reboots.
@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?
@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
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
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
@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.
SET fish_user_paths:/Users/sztadhaus/Library/Android/sdk
worked for me!
Something I discovered today is that set has an append option. So if you want to avoid a bit of redundant typing you can do for instance:
set -Ua fish_user_paths ~/.local/bin
Something I discovered today is that
sethas an append option. So if you want to avoid a bit of redundant typing you can do for instance:set -Ua fish_user_paths ~/.local/bin
When this is done, the fish_variables file is updated with something like:
/home/myusername/\x2elocal/bin/
The problem I have is that I want to sync my whole ~/.config/fish/ directory between machines, since I work in multiple machines. It'd be a great way to keep an awesome shell experience wherever I go. But since tilde is expanded to /home/myusername/ I cannot get it to work. I tried these options in the file fish_variables but nothing works: \x7e/\x2elocal/bin/, $HOME/\x2elocal/bin/, "$HOME"/\x2elocal/bin/.
Another question is why ~/.local/bin is not set default as a PATH in the fish shell, as it is part of systemd spec: https://www.freedesktop.org/software/systemd/man/file-hierarchy.html
When this is done, the fish_variables file is updated with something like:
/home/myusername/\x2elocal/bin/
Unfortunately, the value will be expanded when set, and the tilde won't be expanded later, because that's not how $PATH works (the entry would be broken for every other program, with the exception of bash). That means this won't work, so you'll have to use a global variable for it and set it in config.fish.
Another question is why ~/.local/bin is not set default as a PATH in the fish shell
Fish does not set $PATH by default - it inherits it from your environment. Which is a good default because that means fish gets the same $PATH as other shells. If you want ~/.local/bin to be added by default, ask your distribution to add it, or edit e.g. /etc/login.defs.
@faho thanks for the great answer. In regards to ~/.local/bin I do understand it might not be something fish wants to default. At the same time, the default bash installed with e.g. Ubuntu 18.04.2 LTS (my current install) has that dir set by default in the users .profile. I understand this can be set in other ways, but I though that fish is all about "sane defaults" and that directory is actually a very common "sane default". At the same time I understand it might not be the philosophy of fish to include such a default in fish for the reasons you mentioned.
edit: sorry I just realized this discussion is off topic.
A bit more off-topic stuff, but… my universal variable fish_user_paths is shadowed by a global variable with the same name containing an old value of the variable, but as one single element. I have no idea where it comes from and a recursive search for fish_user_paths in ~/.config/fish does not reveal much. What could be going on?
I am using fish 3.0.2.
> set -Ux fish_user_paths /usr/lib/ccache/bin/ $HOME/.local/bin ...
set: Universal variable 'fish_user_paths' is shadowed by the global variable of the same name.
> set -S fish_user_paths
$fish_user_paths: not set in local scope
$fish_user_paths: set in global scope, exported, with 1 elements
$fish_user_paths[1]: length=134 value=|/usr/lib/ccache/bin/ /home/.../.local/bin ...|
$fish_user_paths: set in universal scope, exported, with 7 elements
$fish_user_paths[1]: length=20 value=|/usr/lib/ccache/bin/|
$fish_user_paths[2]: length=21 value=|/home/.../.local/bin|
$fish_user_paths[3]: ...
set -eg fish_user_paths fixes it for the current shell but if I open a new one, it still has the old PATH.
@spider-mario it's ok to open a new issue, or to ask on Super User or a similar forum.
Your problem is that you have exported a universal variable; this is almost always wrong because it leaks into child fish processes as a global variable.
I have to google this every time and I always end up reading through this thread. I suggest adding a command like fish-add-user-path that is idempotent when adding the same path multiple times, but otherwise is just syntactic sugar for setting fish_user_paths
@boxed i've been trying to get myself adjusted to fish for about two months now. I must've landed on this thread at least a dozen times.
fish_add_path sounds good to me if someone wants to tackle it.
#!/usr/bin/env fish
if argparse -n 'fish-add-user-path' -N 1 'h/help' -- $argv
;
else
exit
end
function add_to_path_if_not_there
set exists 0
# normalize path to end with /
switch $argv
case "*/"
set new_path $argv
case "*"
set new_path "$argv/"
end
for x in (string split " " $fish_user_paths)
if test "$x" = "$new_path"
set exists 1
break
end
end
if test "$exists" = "0"
set -Ux fish_user_paths $fish_user_paths $new_path
end
end
# validate that paths exists
for x in (string split " " $argv)
if test -d $x
;
else
echo "Path '$x' does not exist"
exit
end
end
for x in (string split " " $argv)
add_to_path_if_not_there $x
end
This is the first fish script I wrote so I'm pretty sure it's crap! But it does do The Right Thing mostly. If you pass it several invalid paths it only complains about the first one, not all of them. And it might be a good idea if it can accept invalid paths if you pass a flag.. maybe.
But otherwise this seems to work, even if it's ugly :P
@spider-mario I'm not sure if this addresses your issue, but I added set -eg fish_user_paths to ~/.config/fish/config.fish and the setting now persists all sessions for me.
echo "set -eg fish_user_paths" >> ~/.config/fish/config.fish
Is there a way to set PATH for all users? Like $fish_global_path not _user_.
You can change $PATH in /etc/fish/config.fish which is applied by all users.
Sure, a function is nice, but here is a quick abbreviation that I like just as much.
abbr --add path_add "set --universal --append fish_user_paths"
usage:
path_add \
@ElijahLynn that doesn't validate the path and it's not idempotent.
Can't we reopen this? There is a bad UX problem here. Fish normally cares about this stuff!
@boxed this issue has been pulled in many directions so I am going to lock it. I agree PATH often trips people up and there are probably things that can be improved about it. If you have a suggestion for improving how PATH gets set, please open a new issue.
Most helpful comment
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 :