How to remove a path from $PATH variable in fish?

21

11

I am using fish as my shell in Debian and recently (after some upgrade) whenever I try to use command completion I have:

set: No such file or directory
set: Could not add component /usr/lib/x86_64-linux-gnu/libfm to PATH.
set: No such file or directory

Running this:

echo $PATH 

Gives me this:

/usr/lib/x86_64-linux-gnu/libfm /usr/local/bin /usr/bin /bin /usr/local/games /usr/games

In my system there is no /usr/lib/x86_64-linux-gnu/libfm, so I understand why fish is complaining, but I cannot find how to remove this path from my $PATH variable.

Does anyone know how can I do this?

tomekK

Posted 2014-07-02T12:21:30.300

Reputation: 311

grep -R /usr/lib/x86_64-linux-gnu/libfm ~/.config/fish /usr/share/fish ?? – glenn jackman – 2014-07-02T16:10:26.057

$grep -R /usr/lib/x86_64-linux-gnu/libfm ~/.config/fish /usr/share/fish
/home/superuser/.config/fish/fish_history:grep -R /usr/lib/x86_64-linux-gnu/libfm ~/.config/fish /usr/share/fish
– tomekK – 2014-07-03T06:16:29.083

Answers

34

The 'fish' way of setting the $PATH variable is to actually use set --universal fish_user_paths $fish_user_paths /new/path/here. Then $fish_user_paths is actually prepended to the $PATH variable when a new session starts. The $PATH documentation doesn't currently tell you how to delete it though.

In fish every variable is actually a list (array), and you can conveniently access each item directly by using an index/indice. echo $fish_user_paths will print out a space delimited version of every item in the list, make the spaces newline with the translate function echo $fish_user_paths | tr " " "\n" and then put line numbers on it with the number lines function, echo $fish_user_paths | tr " " "\n" | nl. Then delete it with set --erase --universal fish_user_paths[5]. You must use --universal or it will not work in any new sessions.

If someone has the time, please submit a PR to the repo with this example. I opened an issue here.

tldr;

  1. echo $fish_user_paths | tr " " "\n" | nl // get the number of the one you want to delete, e.g. the 5th one
  2. set --erase --universal fish_user_paths[5] // erase the 5th path universally so it persists in new sessions

Elijah Lynn

Posted 2014-07-02T12:21:30.300

Reputation: 1 021

Why is this so arcane? Shouldn't this be a build in feature and added to the documentation so that people doesn't have to Google and end up here? Oh well.. – Pär Nils Amsen – 2018-01-30T10:12:36.943

I think if we take @clozach's answer here https://superuser.com/a/1212305/30982, which is the addpaths() and removepath() function, and open a PR then that would be the first step to getting it added. Most of the maintainers are pretty good to work with, one seems grumpy to me, but overall I think we would have a good chance. So that is our next step.

– Elijah Lynn – 2018-10-10T16:13:28.310

9

As Elijah says, best practice is to modify the fish_user_paths rather than the global PATH. To avoid ever having to Google this again…

  1. Create a couple of functions that only modify fish_user_paths
  2. Make both functions autoloading

To add to user paths:

function addpaths
    contains -- $argv $fish_user_paths
       or set -U fish_user_paths $fish_user_paths $argv
    echo "Updated PATH: $PATH"
end

To remove a user path if it exists (partial credit to this):

function removepath
    if set -l index (contains -i $argv[1] $PATH)
        set --erase --universal fish_user_paths[$index]
        echo "Updated PATH: $PATH"
    else
        echo "$argv[1] not found in PATH: $PATH"
    end
end

And of course, to make them autoloading:

funcsave addpaths; funcsave removepath

Example Usage:

> addpaths /etc /usr/libexec
Modifying PATH: /usr/local/bin /usr/bin /bin /usr/sbin /sbin
Updated PATH: /etc /usr/libexec /usr/local/bin /usr/bin /bin /usr/sbin /sbin

> removepath /usr/libexec
Modifying PATH: /etc /usr/libexec /usr/local/bin /usr/bin /bin /usr/sbin /sbin
Updated PATH: /etc /usr/local/bin /usr/bin /bin /usr/sbin /sbin

clozach

Posted 2014-07-02T12:21:30.300

Reputation: 653

Note: I've just discovered that this approach won't remove a path added through some other mechanism; Some dot-file cleanup may be in order if you find a path coming back each time you open a new terminal session. – clozach – 2017-08-29T19:51:34.413

This is great, just added to my local! – Elijah Lynn – 2017-11-29T00:07:36.687

3

This should erase paths 6 through the last path:

set -e PATH[6..-1]

The -e flag is erase. See help set.

alxrsngrtn

Posted 2014-07-02T12:21:30.300

Reputation: 31

this will only work for the current session – Daniel – 2019-11-04T12:36:56.810

0

Reset fish_user_paths withtout the path you don't want anymore:

 $ set -U fish_user_paths /usr/local/bin /usr/bin /bin /usr/local/games /usr/game

More info: https://fishshell.com/docs/current/tutorial.html#tut_path

gagarine

Posted 2014-07-02T12:21:30.300

Reputation: 887