78

I source the bashrc's of a few of my friends. So I end up having duplicate entries in my $PATH variable. I am not sure if that is causing commands to take a really long time to start. How does $PATH internally work in bash? Does having more PATHS slow my start up time?

3

6 Answers 6

71

Having more entries in $PATH doesn't directly slow your startup, but it does slow each time you first run a particular command in a shell session (not every time you run the command, because bash maintains a cache). The slowdown is rarely perceptible unless you have a particularly slow filesystem (e.g. NFS, Samba or other network filesystem, or on Cygwin).

Duplicate entries are also a little annoying when you review your $PATH visually, you have to wade through more cruft.

It's easy enough to avoid adding duplicate entries.

case ":$PATH:" in
  *":$new_entry:"*) :;; # already there
  *) PATH="$new_entry:$PATH";; # or PATH="$PATH:$new_entry"
esac

Side note: sourcing someone else's shell script means executing code that he's written. In other words, you're giving your friends access to your account whenever they want.

Side note: .bashrc is not the right place to set $PATH or any other environment variable. Environment variables should be set in ~/.profile. See Which setup files should be used for setting up environment variables with bash?, Difference between .bashrc and .bash_profile.

6
  • 9
    +1: can't emphasize that "giving your friends access to your account" enough emphasis. Even if there is no attempt at doing you harm, their script could be just what they need and still eat your lunch when you source it.
    – msw
    Jun 13, 2011 at 11:41
  • One possible issue with this solution is if $new_entry is already the first entry in PATH, the ":$new_entry:" won't match. I fixed this in my profile by excluding the initial ':' colon. May 19, 2019 at 14:12
  • 1
    @JeffBauer I don't see the problem. I use case :$PATH: and not case $PATH so that it matches even if the entry is first or last. May 19, 2019 at 20:05
  • Is the colon before the double-semicolon on the second line (:;;) a typo? Aug 19, 2022 at 15:30
  • 1
    @BigMcLargeHuge : is a no-op command. I use it before ;; because some shells require a command before ;; (or used to, it looks like modern shells available on Linux don't). Even when not required, explicitly indicating that there's nothing to do is arguably good style, so the reader knows there isn't something missing. Aug 19, 2022 at 15:43
45

I've seen people clean up duplicates from their PATH variable using awk and something like this:

PATH=$(printf "%s" "$PATH" | awk -v RS=':' '!a[$1]++ { if (NR > 1) printf RS; printf $1 }')

You could try adding that to your own bashrc and make sure you source the other files somewhere before running that.

An alternative would be to use the pathmerge utility.

As for your speed problem, this will not affect the startup time of the shell in any significant way but it may save some time doing tab completion for commands, especially when the command is not found in the path and it does repeated searches through the same folders looking for it.

A note on security: You should really heed Gilles' warnings about security here. By sourcing a file owned by another user you are giving a free pass to those users to execute their own code as your user every time you start a shell. If you don't trust those users with your password, you shouldn't be sourcing their shell files.

9
  • 8
    I like the awk one-liner, but it prints a trailing ORS ':'. So I modified it to read PATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
    – gkb0986
    Sep 18, 2013 at 6:01
  • The trailing : is not only a cosmetic issue. It is the same as adding . to your path, which is potentially dangerous.
    – wisbucky
    Apr 24, 2017 at 23:31
  • I've edited the answer to include the fix from gkb0986.
    – Tim Lesher
    Jan 19, 2018 at 13:24
  • @TimLesher The reason I'd never edited than into by answer is that it doesn't work for me .... and the original without it does work (including not leaving a trailing separator. I don't know what the difference is.
    – Caleb
    Jan 19, 2018 at 14:07
  • 1
    @gkb0986 This solution still fails if the path contains an escaped space, such as PATH=/bin:/foo\ bar:/usr/bin. I found a variant that avoids this at unix.stackexchange.com/a/124517/106102
    – Alcamtar
    Feb 14, 2019 at 20:49
23

Based on @Gilles answer you may wrap it in a function to minimize typing:

function addToPATH {
  case ":$PATH:" in
    *":$1:"*) :;; # already there
    *) PATH="$1:$PATH";; # or PATH="$PATH:$1"
  esac
}

addToPATH /Applications/AIRSDK_Compiler/bin
addToPATH ~/.local/lib/npm/bin
2
  • 1
    Most practically-usable (high-level, perhaps) answer.
    – ijoseph
    Aug 29, 2018 at 17:42
  • Very nice addition to OG answer Jul 31, 2020 at 15:33
2

Only the first match in $PATH is executed, so any subsequent entries are not processed after that. That's why you should sometimes revise the order of the entries in your $PATH to make your environment behave as expected.

To answer your question: this shouldn't be the cause of slow startup.

3
  • 1
    But it takes longer when I type a command that does not exist. It will search the same folder twice for the command.
    – balki
    Jun 13, 2011 at 8:50
  • @balki You mean completing a command with TAB? In that case you should check whether you complete definition doesn't look like complete -c which -a. You should delete the -a parameter. You can check that by issuing the command: complete | grep which.
    – Rajish
    Jun 13, 2011 at 9:34
  • It could still be an issue if it searches the same directory that it's not in multiple times before finding it.
    – Random832
    Jun 13, 2011 at 13:44
0

PATH manipulation (manipulating any colon-separated list) is easy. I use Stephen Collyer's bash_path_funcs, described in Linux Journal way back in 2000:

https://www.linuxjournal.com/article/3645 https://www.linuxjournal.com/article/3768 https://www.linuxjournal.com/article/3935

The addpath function adds an entry to a path only if it is not there in the first place. delpath -n deletes all non-existent directories from a path.

You can get the pathfunc.tgz file from https://web.archive.org/web/20061210054813/http://www.netspinner.co.uk:80/Downloads/pathfunc.tgz

-1

To prevent duplicate entries in my PATH, I had to put the following in BOTH ~/.bash_profile and ~/.bashrc:

PATH=$(echo $(sed 's/:/\n/g' <<< $PATH | sort | uniq) | sed -e 's/\s/':'/g')

The main drawback is that it sorts PATH entries, but I think I can live with that.

1
  • 7
    The order of the search PATH is pretty important. Oct 24, 2019 at 6:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .