6

I have installed some tools and put it under $HOME/tools/ and each tool has its own /bin directory that contains the executable program. I now have the path to each individual /bin in my $HOME/.bashrc file like this:

export PATH=$PATH:$HOME/tools/tool1/bin
export PATH=$PATH:$HOME/tools/tool2/bin
...

I'm wondering if it's OK to write the following for all the tools?

export PATH=$PATH:$HOME/tools

If it doesn't work, what is the best way to do this?

2
  • You don't need the export, PATH is already marked for export and will be put into child process' environments.
    – llua
    Feb 12, 2014 at 0:04
  • OK, I see. I saw many people still use export.. Feb 12, 2014 at 14:58

5 Answers 5

8

Adding a directory to PATH only makes the executables in this directory available as bare command names. This does not extend to subdirectories.

You can put a loop in your .profile (not .bashrc) to add multiple directories, for example:

for d in ~/tools/*/bin; do
  PATH="$PATH:$d"
done

(You don't need to repeat export: when a variable is exported, it stays exported, and modifications are reflected in the environment).

If you create new directories under tools, this will not be reflected in your ongoing session, only the next time .profile is read. If this is not satisfactory, you can use a different approach: put a single directory such as ~/bin in your PATH, and when you install software, create symbolic links in ~/bin. Stow (or its alternative XStow) is a good way of doing this; see Keeping track of programs for an overview of how this works.

5
  • thanks for the explanation. I wanted to vote for your answer but don't have enough reputation to do that yet... Feb 12, 2014 at 3:34
  • I tried Stow and it's pretty cool. I do have a question on the link you mentioned. In your example, the executables were installed in /usr/local/stow/PROGRAM_NAME/bin and if you just issue "stow PROGRAM_NAME", all the subdirectories under /usr/local/stow/PROGRAM_NAME are also linked and in our server it looks like bin -> stow/PROGRAM_NAME/bin. However, when I tried to include /usr/local/stow in the $PATH, the executable in stow/PROGRAM_NAME/bin actually can be invoked. Based on what people said here, this is contradictory as bin->stow/PROGRAM_NAME/bin is a subdirectory now, right? Feb 12, 2014 at 6:22
  • I don't understand exactly what you did. There wouldn't be any executable in /usr/local/stow, but they are linked in /usr/local/bin in the PATH, that's where they're found. Feb 12, 2014 at 14:55
  • i read the GNU manual and my understanding is that stow can apply to a package directory, not a single executable. And "the subdirectory is created within the target, and its contents are symlinked, rather than just creating a symlink for the directory" so that's what I saw.. link is here gnu.org/software/stow/manual/stow.html Feb 12, 2014 at 15:02
  • i came up with my way of dealing with subdirectory under PROGRAM_NAME, if the program already has a /bin directory, I just stow that PROGRAM_NAME/bin directory. Otherwise, I create a /bin directory and symlink myself all the executables I need, and then stow the new PROGRAM_NAME/bin directory. This seem to work best for me and not worry about using --ignore to get rid of many things I don't want to be stowed. Feb 12, 2014 at 18:12
1

Adding things to the $PATH is not recursive. Only the directories that are present in $PATH will be searched by your shell when it's looking for executables to run.

To see what's currently on your $PATH:

$ printenv PATH

4 common tactics when dealing with many directories such as you're facing is to either:

  1. add them individually, which is perfectly fine, $PATH can be fairly long.
  2. use the command alternatives (man page) to create symbolic links to the various executables in the differing directories. This trades a long $PATH for having to maintain symbolic links to the various executables.
  3. create either aliases or wrapper .sh scripts that can exist in a common directory and will dynamically change the $PATH or other environment variables as needed.
  4. Use a tool to manage your environment such as modules.

Further background

Where I used to work we used a technology we developed internally called use scripts which operators would run commands such as use X, where X was the name + version of a CAD/CAM software package such as Xilinx. This would automatically add the appropriate directories and environment variables to the user's shell. When they were done with X they could say use -no X. to unload this tool from their environment.

More exotic methods

Another approach for building up your $PATH but in a more modular way would be to mimic the way most systems work by creating a /etc/profile.d directory. You can make your own, or even utilize your system's /etc/profile.d directory to facilitate the adding of things to your environment and/or $PATH.

For example, if you look at your /etc/bashrc you might notice this construct:

for i in /etc/profile.d/*.sh; do
    if [ -r "$i" ]; then
        if [ "$PS1" ]; then
            . "$i"
        else
            . "$i" >/dev/null
        fi
    fi
done

You could model yourself something similar where you could put fragments of things you want to get added to your $PATH + environment.

When this loop runs it will incorporate the contents of the various files in your version of the profile.d directory. You'd just need to create files in your directory with content like this:

file1.sh

PATH=$PATH:$HOME/tools/tool1/bin

file2.sh

PATH=$PATH:$HOME/tools/tool2/bin

You can organize this directory anyway you want.

3
  • OK. I got that. What would you do to avoid typing out all the directories? Is there a cleaner way? Feb 12, 2014 at 0:00
  • @user2157668 - where I used to work we actually developed a internal tool similar to modules. We supported 100's of CAD/CAM applications though. In lieu of doing that I would try parameterize the components as much as possible and then construct the $PATH using these variables.
    – slm
    Feb 12, 2014 at 0:06
  • thanks for the explanation. I wanted to vote for your answer but don't have enough reputation to do that yet... Feb 12, 2014 at 3:37
0

No that will not work ! that will add only $HOME/tools to your path.

The principle of each tool having it's own bin dir doesn't fit well really, think about /bin or /usr/bin everything goes in there (well nearly everything) each package does not have it's own bin dir. ( Orthogonal ? )

3
  • you mean I can create symbolic links in a $HOME/tools/bin/ directory and link tool1 and tool2 there? Feb 11, 2014 at 23:59
  • No, I didn't say that, and that is a good idea. Add to your post to clarify maybe. tks
    – X Tian
    Feb 12, 2014 at 0:03
  • I wanted to vote for your answer but don't have enough reputation to do that yet... Feb 12, 2014 at 3:36
0

You could do either of the following

  1. Just add all the bin folders like you have done

  2. Create another bin folder such as $HOME/bin, and then symbolic link the relevant binaries into $HOME/bin, and then add $HOME/bin to your path

  3. If you have admin rights to the machine, then use /usr/local for you application compilations, and then everything be in place automatically, and you don't need to change your path at all. i.e. ./configure on it's on will automatically make sure that the application will install in /usr/local

  4. Use something like modules environment http://modules.sourceforge.net/, which then you can add to your environment, and depending the application you want to run, then you can change the environment.

I hope that makes sense.

1
  • thanks for the explanation. I wanted to vote for your answer but don't have enough reputation to do that yet... Feb 12, 2014 at 3:37
0

Try this way:
export PATH="$PATH:$(du "~/tools/" | cut -f2 | tr '\n' ':' | sed 's/:*$//')"
This will add ~/tools itself along with all its subdirectories into $PATH
Explanation:
- du will display all the subdirectories info each line
- cut -f2 will extract the second column, i.e., the names of the subdirectories
- tr '\n' ':' will change each link break into a colon. This will join all lines into a single line and the subdirectories are delimited by a colon
- sed 's/:*$//' will remove the last colon

You must log in to answer this question.

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